Buscar..


Introducción

Véase también el tema separado sobre resolución de sobrecarga

Observaciones

Se pueden producir ambigüedades cuando un tipo puede convertirse implícitamente en más de un tipo y no hay una función coincidente para ese tipo específico.

Por ejemplo:

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 

¿Qué es la sobrecarga de funciones?

La sobrecarga de funciones es tener múltiples funciones declaradas en el mismo ámbito con el mismo nombre exacto en el mismo lugar (conocido como alcance ) que difiere solo en su firma , es decir, los argumentos que aceptan.

Supongamos que está escribiendo una serie de funciones para las capacidades de impresión generalizadas, comenzando con std::string :

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

Esto funciona bien, pero suponga que quiere una función que también acepte un int y que también lo imprima. Podrías escribir:

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

Pero debido a que las dos funciones aceptan diferentes parámetros, simplemente puede escribir:

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

Ahora tiene 2 funciones, ambas con nombre de print , pero con firmas diferentes. Uno acepta std::string , el otro es int . Ahora puedes llamarlos sin preocuparte por nombres diferentes:

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

En lugar de:

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

Cuando tiene funciones sobrecargadas, el compilador infiere a cuál de las funciones llamar desde los parámetros que le proporciona. Se debe tener cuidado al escribir sobrecargas de funciones. Por ejemplo, con conversiones de tipo implícitas:

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

Ahora no está claro de inmediato a qué sobrecarga de print se llama cuando escribe:

print(5);

Y es posible que necesites darle algunas pistas a tu compilador, como:

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

También se debe tener cuidado al escribir sobrecargas que aceptan parámetros opcionales:

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

Debido a que no hay forma de que el compilador sepa si una llamada como print(17) está destinada a la primera o la segunda función debido al segundo parámetro opcional, esto no se compilará.

Tipo de retorno en la sobrecarga de funciones

Tenga en cuenta que no puede sobrecargar una función en función de su tipo de retorno. Por ejemplo:

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

int getValue()
{
  return 0;
}

int x = getValue();

Esto provocará un error de compilación, ya que el compilador no podrá determinar a qué versión de getValue llamar, aunque el tipo de retorno esté asignado a un int .

Función de miembro cv-qualifier Sobrecarga

Las funciones dentro de una clase pueden sobrecargarse cuando se accede a ellas mediante una referencia calificada por el CV a esa clase; esto es más comúnmente usado para sobrecargar para const , pero también puede ser usado para sobrecargar para volatile y const volatile . Esto se debe a que todas las funciones miembro no estáticas toman this como un parámetro oculto, al que se aplican los calificadores cv. Esto se usa más comúnmente para sobrecargar para const , pero también se puede usar para volatile y const volatile .

Esto es necesario porque solo se puede llamar a una función miembro si está al menos tan calificada como CV como la instancia a la que se llama. Mientras que una instancia no const puede llamar a miembros const y no const , una instancia const solo puede llamar miembros const . Esto permite que una función tenga un comportamiento diferente dependiendo de los calificadores cv de la instancia que llama, y ​​le permite al programador no permitir funciones para un calificador (es) calificador (es) no deseado (s) al no proporcionar una versión con ese calificador (es).

Una clase con algunos básicos print método podría ser const sobrecargado de este 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"
}

Este es un principio clave de la corrección de const : Al marcar las funciones miembro como const , se les permite llamar en instancias const , lo que a su vez permite que las funciones tomen instancias como punteros / referencias const si no necesitan modificarlas. Esto permite que el código especifique si modifica el estado tomando parámetros no modificados como const y parámetros modificados sin calificadores cv, lo que hace que el código sea más seguro y más legible.

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 común de esto es declarar los accesores como const , y los mutadores como no const .


Ningún miembro de clase puede ser modificado dentro de una función miembro const . Si hay algún miembro que realmente necesita modificar, como bloquear un std::mutex , puede declararlo como 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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow