Ricerca…


introduzione

Vedi anche argomento separato su Risoluzione overload

Osservazioni

Le ambiguità possono verificarsi quando un tipo può essere convertito implicitamente in più di un tipo e non esiste una funzione di corrispondenza per quel tipo specifico.

Per esempio:

void foo(double, double);
void foo(long, long);

//Call foo with 2 ints
foo(1, 2); //Function call is ambiguous - int can be converted into a double/long at the same time 

Cos'è il sovraccarico di funzione?

L'overloading delle funzioni sta avendo più funzioni dichiarate nello stesso ambito con lo stesso identico nome nello stesso punto (noto come scope ) che differisce solo nella loro firma , vale a dire gli argomenti che accettano.

Supponiamo che stiate scrivendo una serie di funzioni per le capacità di stampa generalizzate, iniziando con std::string :

void print(const std::string &str)
{
    std::cout << "This is a string: " << str << std::endl;
}

Funziona bene, ma supponiamo che tu voglia una funzione che accetta anche un int e stampa anche quello. Potresti scrivere:

void print_int(int num)
{
    std::cout << "This is an int:  " << num << std::endl;
}

Ma poiché le due funzioni accettano parametri diversi, puoi semplicemente scrivere:

void print(int num)
{
    std::cout << "This is an int: " << num << std::endl;
}

Ora avete 2 funzioni, entrambe denominate print , ma con diverse firme. Uno accetta std::string , l'altro un int . Ora puoi chiamarli senza preoccuparti di nomi diversi:

print("Hello world!"); //prints "This is a string: Hello world!"
print(1337);           //prints "This is an int: 1337"

Invece di:

print("Hello world!");
print_int(1337);

Quando hai sovraccaricato le funzioni, il compilatore deduce quale delle funzioni chiamare dai parametri che le hai forniti. Bisogna fare attenzione quando si scrivono sovraccarichi di funzione. Ad esempio, con conversioni di tipo implicite:

void print(int num)
{
    std::cout << "This is an int: " << num << std::endl;
}
void print(double num)
{
    std::cout << "This is a double: " << num << std::endl;
}

Ora non è immediatamente chiaro quale sovraccarico di print viene chiamato quando scrivi:

print(5);

E potrebbe essere necessario fornire al compilatore alcuni indizi, come:

print(static_cast<double>(5));
print(static_cast<int>(5));
print(5.0);

È necessario prestare attenzione quando si scrivono sovraccarichi che accettano parametri facoltativi:

// WRONG CODE
void print(int num1, int num2 = 0)    //num2 defaults to 0 if not included
{ 
    std::cout << "These are ints: << num1 << " and " << num2 << std::endl;
}
void print(int num)
{
    std::cout << "This is an int: " << num << std::endl;
}

Perché non c'è modo per il compilatore di dire se una chiamata come print(17) è pensata per la prima o la seconda funzione a causa del secondo parametro opzionale, questo non riuscirà a compilare.

Tipo di ritorno Sovraccarico funzione

Si noti che non è possibile sovraccaricare una funzione in base al suo tipo di ritorno. Per esempio:

// WRONG CODE
std::string getValue()
{
  return "hello";
}

int getValue()
{
  return 0;
}

int x = getValue();

Ciò causerà un errore di compilazione in quanto il compilatore non sarà in grado di determinare quale versione di getValue chiamare, anche se il tipo restituito è assegnato a un int .

Funzione membro qualifica cv Sovraccarico

Le funzioni all'interno di una classe possono essere sovraccaricate per quando sono accessibili tramite un riferimento qualificato cv a quella classe; questo è più comunemente usato per il sovraccarico di const , ma può essere usato anche per sovraccaricare volatile e const volatile . Questo perché tutte le funzioni membro non statiche prendono this come parametro nascosto, al quale vengono applicati i qualificatori cv. Questo è più comunemente usato per sovraccaricare const , ma può anche essere usato per volatile e const volatile .

Questo è necessario perché una funzione membro può essere chiamata solo se è almeno classificata come cv come l'istanza su cui è chiamata. Mentre un non const istanza può chiamare sia const e non const membri, un const istanza può chiamare solo const membri. Ciò consente a una funzione di avere un comportamento diverso a seconda dei cv-qualificatori dell'istanza chiamante e consente al programmatore di disabilitare le funzioni per un qualificatore cv indesiderato non fornendo una versione con quel qualificatore (i).

Una classe con un metodo di print base potrebbe essere sovraccaricata const modo:

#include <iostream>

class Integer
{
    public:
        Integer(int i_): i{i_}{}

        void print()
        {
            std::cout << "int: " << i << std::endl;
        }

        void print() const
        {
            std::cout << "const int: " << i << std::endl;
        }

    protected:
        int i;
};

int main()
{
    Integer i{5};
    const Integer &ic = i;
    
    i.print(); // prints "int: 5"
    ic.print(); // prints "const int: 5"
}

Questo è un principio chiave della correttezza const : contrassegnando le funzioni membro come const , è possibile che vengano chiamate su istanze const , che a loro volta consentono alle funzioni di assumere istanze come riferimenti / riferimenti const se non è necessario modificarle. Ciò consente al codice di specificare se modifica lo stato prendendo parametri non modificati come parametri const e modificati senza qualificatori di cv, rendendo il codice più sicuro e più leggibile.

class ConstCorrect 
{
  public:
    void good_func() const 
    {
        std::cout << "I care not whether the instance is const." << std::endl;
    }

    void bad_func() 
    {
        std::cout << "I can only be called on non-const, non-volatile instances." << std::endl;
    }
};

void i_change_no_state(const ConstCorrect& cc) 
{
    std::cout << "I can take either a const or a non-const ConstCorrect." << std::endl;
    cc.good_func(); // Good.  Can be called from const or non-const instance.
    cc.bad_func();  // Error.  Can only be called from non-const instance.
}

void const_incorrect_func(ConstCorrect& cc) 
{
    cc.good_func(); // Good.  Can be called from const or non-const instance.
    cc.bad_func();  // Good.  Can only be called from non-const instance.
}

Un uso comune di questo è dichiarare accessors come const , e mutatori come non- const .


Nessun membro della classe può essere modificato all'interno di una funzione membro const . Se c'è un membro che devi veramente modificare, come il blocco di std::mutex , puoi dichiararlo come mutable :

class Integer
{
    public:
        Integer(int i_): i{i_}{}

        int get() const
        {
            std::lock_guard<std::mutex> lock{mut};
            return i;
        }

        void set(int i_)
        {
            std::lock_guard<std::mutex> lock{mut};
            i = i_;
        }

    protected:
        int i;
        mutable std::mutex mut;
};


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow