Zoeken…


Invoering

Zie ook een afzonderlijk onderwerp over overbelastingsresolutie

Opmerkingen

Onduidelijkheden kunnen optreden wanneer een type impliciet kan worden geconverteerd naar meer dan één type en er geen overeenkomende functie is voor dat specifieke type.

Bijvoorbeeld:

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 

Wat is functieoverbelasting?

Bij functie-overbelasting worden meerdere functies gedeclareerd in hetzelfde bereik met exact dezelfde naam op dezelfde plaats (bekend als bereik ) die alleen in hun handtekening verschillen , wat betekent dat de argumenten die ze accepteren.

Stel dat u een reeks functies schrijft voor algemene afdrukmogelijkheden, beginnend met std::string :

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

Dit werkt prima, maar stel dat u een functie wilt die ook een int accepteert en die ook afdrukt. Je zou kunnen schrijven:

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

Maar omdat de twee functies verschillende parameters accepteren, kunt u eenvoudig schrijven:

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

Nu heb je 2 functies, beide genaamd print , maar met verschillende handtekeningen. De ene accepteert std::string , de andere een int . Nu kun je ze bellen zonder je zorgen te maken over verschillende namen:

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

In plaats van:

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

Wanneer u overbelaste functies hebt, leidt de compiler af welke van de functies u moet aanroepen uit de parameters die u opgeeft. Voorzichtigheid is geboden bij het overladen van functies. Bijvoorbeeld, met impliciete type conversies:

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;
}

Nu is het niet meteen duidelijk welke overbelasting print wordt genoemd wanneer je schrijft:

print(5);

En misschien moet u uw compiler enkele aanwijzingen geven, zoals:

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

Enige voorzichtigheid is ook geboden bij het schrijven van overbelastingen die optionele parameters accepteren:

// 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;
}

Omdat de compiler op geen enkele manier weet of een aanroep zoals print(17) bedoeld is voor de eerste of tweede functie vanwege de optionele tweede parameter, kan dit niet worden gecompileerd.

Retourtype in functie Overbelasting

Merk op dat u een functie niet kunt overbelasten op basis van het retourtype. Bijvoorbeeld:

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

int getValue()
{
  return 0;
}

int x = getValue();

Dit veroorzaakt een compilatiefout, omdat de compiler niet kan bepalen welke versie van getValue moet worden getValue , hoewel het retourtype is toegewezen aan een int .

Lid Functie cv-qualifier Overbelasting

Functies binnen een klasse kunnen worden overbelast wanneer ze worden benaderd via een cv-gekwalificeerde verwijzing naar die klasse; dit wordt meestal gebruikt om te overbelasten voor const , maar kan ook worden gebruikt om te overbelasten voor volatile en const volatile . Dit komt omdat alle niet-statische lidfuncties this als een verborgen parameter beschouwen, waarop de cv-kwalificaties worden toegepast. Dit wordt meestal gebruikt om te overbelasten voor const , maar kan ook worden gebruikt voor volatile en const volatile .

Dit is nodig omdat een lidfunctie alleen kan worden aangeroepen als deze minstens zo cv-gekwalificeerd is als de instantie waarop deze is ingeschakeld. Terwijl een niet- const instantie zowel const als niet- const leden kan aanroepen, kan een const instantie alleen const leden aanroepen. Hierdoor kan een functie een ander gedrag hebben, afhankelijk van de cv-kwalificaties van de aanroepende instantie, en kan de programmeur functies voor een ongewenste cv-kwalificatie (s) weigeren door geen versie met die kwalificatie (s) te verstrekken.

Een klasse met een aantal elementaire print methode kan worden const overbelast als volgt:

#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"
}

Dit is een kernprincipe van const correctheid: door lidfuncties als const markeren, mogen ze op const instanties worden opgeroepen, waardoor functies op hun beurt instanties als const pointers / referenties kunnen opnemen als ze deze niet hoeven te wijzigen. Hiermee kan code opgeven of de status wordt gewijzigd door niet-gemodificeerde parameters als const en gewijzigde parameters zonder cv-kwalificaties te nemen, waardoor code zowel veiliger als leesbaarder wordt.

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.
}

Een gebruikelijk gebruik hiervan is het verklaren van accessors als const en mutators als niet- const .


Binnen een functie voor const leden kunnen geen klassenleden worden gewijzigd. Als er een lid is dat u echt moet wijzigen, zoals het vergrendelen van een std::mutex , kunt u dit als mutable verklaren:

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow