Introducción a los conceptos básicos de C++ (medio): sobrecarga de funciones, referencias, funciones en línea

Tabla de contenido

introducción

1. Sobrecarga de funciones

1.1 Concepto

1.2 Ejemplos

① Diferentes tipos de parámetros

② El número de parámetros es diferente

③ El orden de los tipos de parámetros es diferente

Aviso

1.3 Principio

Por ejemplo

Aviso

2. Cita

2.1 Declaraciones y definiciones referenciadas

2.2 Características de las referencias

2.3 La diferencia entre referencias y punteros

2.4 Referencias comunes

2.4.1 Características citadas con frecuencia

2.5 Aplicación de referencia

3. Funciones en línea

3.1 Cómo declarar una función en línea

3.2 Ventajas de las funciones en línea

3.3 Consideraciones para funciones en línea


introducción

Esta serie tiene como objetivo proporcionar a los principiantes una guía introductoria de C++ completa y fácil de entender . Comenzaremos con palabras clave de C++ y exploraremos gradualmente varios aspectos de C++, incluidos espacios de nombres, entrada y salida, características de funciones y algunas características nuevas de C++11auto , como palabras clave, bucles for basados ​​en rangos y nullptr. Cada tema tendrá una explicación concisa y un código de muestra para ayudarlo a comprender y aplicar mejor este conocimiento.

Ya sea que recién esté comenzando con la programación o quiera cambiar a C++ desde otro lenguaje de programación, esta guía lo ayudará a construir una base sólida en C++. Al estudiar esta serie, dominará los conceptos básicos y las características comunes de C++, lo que sentará una base sólida para el estudio y el desarrollo de proyectos posteriores.

1. Sobrecarga de funciones

1.1 Concepto

La sobrecarga de funciones es una característica muy útil en la programación de C++ . Nos permite declarar múltiples funciones con el mismo nombre en el mismo alcance , pero estas funciones tienen diferentes tipos de parámetros o número de parámetros o diferente orden de parámetros. A través de la sobrecarga de funciones, podemos usar el mismo nombre de función para representar diferentes operaciones, mejorando así la flexibilidad y legibilidad del código.

1.2 Ejemplos

① Diferentes tipos de parámetros

int Add(int left, int right)
{
    cout << "int Add(int left, int right)" << endl;
    return left + right;
}


double Add(double left, double right)
{
    cout << "double Add(double left, double right)" << endl;
    return left + right;
}

② El número de parámetros es diferente

void fun(int a)
{
    cout << "fun(int a)" << endl;
}

void fun()
{
    cout << "fun()" << endl;
}

③ El orden de los tipos de parámetros es diferente

void fun(int a, double b)
{
    cout << "fun(int a, double b)" << endl;
}

void fun(double a, int b)
{
    cout << "fun(double a, int b)" << endl;
}

Al llamar a estas funciones, el usuario selecciona la función de acuerdo con los requisitos y pasa los parámetros reales de acuerdo con el prototipo de función , y el compilador seleccionará la función adecuada para llamar de acuerdo con el tipo y la cantidad de parámetros pasados ​​a la función . De esta forma, podemos usar el mismo nombre de función para representar diferentes operaciones.

Aviso

La validez de la sobrecarga de funciones se distingue según la lista de parámetros de la función, independientemente del tipo de retorno . En C++, el tipo de retorno de una función no afecta el proceso de selección para la sobrecarga de funciones. Esto se debe a que el tipo de retorno de la función no se usa para resolver la ambigüedad de la sobrecarga de funciones cuando se llama a la función.

La solución de sobrecarga de la función es que el compilador selecciona la función correcta para llamar de acuerdo con el tipo y la cantidad de parámetros pasados ​​a la función. Cuando el compilador llama a una función, buscará una declaración de función coincidente basada en los parámetros realmente pasados. Si se encuentra una declaración de función con una lista de parámetros coincidentes, se llama a la función correspondiente, independientemente de si los tipos de retorno de estas funciones son los mismos.

1.3 Principio

  1. Manipulación de nombres (Name Mangling) : en C++, la sobrecarga de funciones implica la distinción de nombres de funciones. Dado que la sobrecarga de funciones puede tener el mismo nombre de función, para distinguir estas funciones durante la compilación, el compilador de C++ modificará el nombre de la función, también conocido como manipulación de nombres (Name Mangling). La manipulación de nombres es la codificación del nombre de la función y la información de la lista de parámetros en una cadena única, lo que da como resultado diferentes nombres de función después de la compilación. De esta manera, el mismo nombre de función se vuelve diferente después de la compilación, por lo que se puede distinguir la sobrecarga de funciones.

  2. Coincidencia de parámetros : al realizar una llamada a una función, el compilador de C++ hará coincidir la función apropiada de acuerdo con el tipo y la cantidad de parámetros pasados. El compilador compara los tipos de parámetros reales y formales pasados ​​a la función para encontrar una declaración de función coincidente. La coincidencia de parámetros se realiza en tiempo de compilación, no en tiempo de ejecución.

  3. Resolución de llamada de función : una vez que el compilador coincide con una declaración de función adecuada, genera la llamada de función correspondiente. Debido a la manipulación de nombres, el nombre de llamada real de una función puede no ser exactamente el mismo que el nombre de la función en el código fuente.

Por ejemplo

int add(int a, int b);
float add(float a, float b);

El compilador puede add(int, int)decorar el nombre de la función con "_Z3addii" y add(float, float)el nombre de la función con "_Z3addff" . Por lo tanto, el nombre de la función llamada en el código fuente y el nombre de la función generada real pueden ser diferentes

int sum1 = add(5, 10);          // 实际调用的函数名可能为"_Z3addii"
float sum2 = add(3.14f, 2.71f); // 实际调用的函数名可能为"_Z3addff"

Aviso

Los métodos y reglas específicos de decoración de nombres pueden ser diferentes en diferentes compiladores, lo que también genera ligeras diferencias en cómo los diferentes compiladores manejan la sobrecarga de funciones . Para mantener la compatibilidad con versiones anteriores, C ++ proporciona extern "C"un mecanismo para declarar la decoración del nombre de la función del lenguaje C en el código C ++.

2. Cita

En C++, las referencias son un mecanismo para crear alias de variables . Las referencias nos permiten acceder al valor de una variable existente por su nombre, en lugar de crear un nuevo espacio de almacenamiento. Las referencias introducen una sintaxis más intuitiva y concisa en C++ y proporcionan una forma más segura y eficiente de manipular variables.

2.1 Declaraciones y definiciones referenciadas

Las referencias se &declaran mediante símbolos. Al declarar una referencia, debemos inicializarla en el destino de la referencia, la variable a la que se hará referencia. Una vez que se inicializa una referencia, siempre se referirá a esa variable y no se puede volver a vincular a otra variable .

Tipo y nombre de variable de referencia (nombre de objeto) = entidad de referencia;

int num = 10;
int& ref = num;  // 引用声明和初始化

La primera línea de código indica que se abre un espacio en el espacio para almacenar el valor 10, y se llama num.La segunda línea de código indica que le doy a este espacio otro nombre ref . Ambos nombres pueden operar en este espacio, y el efecto es el mismo .

Nota: El tipo de referencia debe ser del mismo tipo que la entidad referenciada, claro que hay excepciones, que se explicarán más adelante.

2.2 Características de las referencias

  1. Alias : una referencia proporciona un alias para una variable. Por referencia, podemos usar diferentes nombres para acceder a la misma variable.

  2. Sin referencias nulas : C ++ requiere que las referencias se inicialicen cuando se declaran, y una vez inicializadas, el objeto al que se refieren no se puede cambiar.

  3. Sin dirección independiente : la referencia en sí no ocupa espacio en la memoria, es solo un alias para la variable. Por lo tanto, la dirección no se puede obtener para la referencia.

  4. Paso de parámetros : Las referencias son especialmente útiles en el paso de parámetros de función.Puede pasar parámetros por referencia para darse cuenta del efecto de la modificación de parámetros dentro de la función en las variables originales.

2.3 La diferencia entre referencias y punteros

Las referencias y los punteros son dos mecanismos diferentes de creación de alias de variables en C++, con las siguientes diferencias principales entre ellos:

  1. Inicialización y reenlace : las referencias deben inicializarse cuando se declaran y, una vez inicializadas, no se pueden volver a enlazar con otras variables. El puntero no se puede inicializar y se puede volver a apuntar a otras variables.

  2. Referencia nula : C++ no permite la creación de una referencia nula, es decir, la referencia debe estar vinculada a un objeto existente. Sin embargo, los punteros no pueden apuntar a nada (nullptr).

  3. Sintaxis : las referencias &se declaran mediante símbolos y los punteros *se declaran mediante símbolos.

  4. Ocupación de memoria : la referencia en sí no ocupa espacio de memoria adicional, mientras que el puntero necesita almacenar la dirección del objeto de destino, ocupando una cierta cantidad de espacio de memoria.

2.4 Referencias comunes

Una referencia constante (referencia const) es un tipo especial de referencia que se usa en C++ para restringir la modificación de objetos a los que se accede a través de referencias. Al declarar una referencia como const, le decimos al compilador que el objeto al que apunta la referencia es de solo lectura y que no se permite ninguna modificación del objeto a través de la referencia .

Una referencia constante se implementa agregando palabras clave a la declaración de referencia const, y su forma de declaración es:

const T& ref = 引用实体;
//T是要引用的对象类型

2.4.1 Características citadas con frecuencia

  1. Acceso de solo lectura : Con referencias constantes, solo podemos leer el valor del objeto referenciado y no podemos modificarlo. Cualquier intento de modificar un objeto a través de una referencia constante dará como resultado un error de compilación.

  2. Requisitos de inicialización : las referencias constantes deben inicializarse en el momento de la declaración y solo pueden referirse a una variable o constante del mismo tipo.

  3. Objeto temporal : una referencia constante se puede vincular a un objeto temporal (rvalue), pero dado que el objeto temporal se destruirá después de que finalice la expresión, solo se puede acceder al valor del objeto temporal y no se puede modificar.

   Ejemplo para el tercer punto

int& ref = 10; //错误 10为右值,不能通过ref进行修改
const int& ref = 10; //正确 此时ref为常引用不可修改内容

2.5 Aplicación de referencia

1. Paso de parámetros de función : Pasar parámetros por referencia puede realizar la modificación de la variable original dentro de la función. Simplificar el uso de punteros.

void increment(int& x) {
    x++;
}

int num = 10;
increment(num);
// 现在num的值为11

2. Valor devuelto: La función puede devolver el resultado por referencia, evitando la creación de variables temporales.

int& findLargest(int& a, int& b) {
    return (a > b) ? a : b;
}

int a = 10, b = 15;
int& largest = findLargest(a, b);
largest = 20;
// 现在b的值为20,即largest为b的引用

3. Evite la copia : las referencias pueden evitar la copia de objetos y mejorar la eficiencia de ejecución del código.

void processLargeObject(const LargeObject& obj) {
    // 处理大对象的操作,不需要复制对象
}

Aquí se utiliza una referencia constante, lo que significa que el objeto no se modificará dentro de la función.

Aviso

Al devolver el valor en el segundo punto, tenga cuidado de no devolver la referencia de variable temporal

int& fun()
{
    int a = 10;
    return a;
}

Por ejemplo, en este código, la variable a será destruida inmediatamente después de la ejecución de la función, si todavía se usa como alias de acuerdo con la referencia en este momento, es una operación ilegal para causar incertidumbre en el resultado.

3. Funciones en línea

Función en línea (Inline Function) es un mecanismo de optimización de funciones en C ++, que se utiliza para insertar el código del cuerpo de la función directamente en el sitio de llamada cuando el compilador está compilando, en lugar de ejecutarlo a través de una llamada de función. Si lo hace, puede evitar la sobrecarga de las llamadas a funciones y mejorar la eficiencia de ejecución del código.

3.1 Cómo declarar una función en línea

En C++, inlinese usa una palabra clave para declarar una función en línea. Normalmente, puede usar inlinela palabra clave en funciones miembro definidas dentro de una clase para declararlas en línea. Para las funciones definidas fuera de la clase, puede usar inlinepalabras clave en la declaración y definición de la función.

Funciones en línea definidas dentro de una clase:

class MyClass {
public:
    inline void myFunction() {
        // 函数体代码
    }
};

Funciones en línea definidas fuera de la clase

// 在函数声明处使用inline关键字
inline void myFunction();

// 在函数定义处使用inline关键字
inline void myFunction() {
    // 函数体代码
}

3.2 Ventajas de las funciones en línea

  1. Reduzca la sobrecarga de llamadas a funciones : cuando se llama a una función, el estado de ejecución actual se guardará en la pila, luego saltará a la función llamada y luego regresará al punto de llamada después de la ejecución. Este proceso implica la creación y destrucción de múltiples marcos de pila. . El código de la función en línea se insertará directamente en el punto de llamada, evitando estos gastos generales adicionales y mejorando así la eficiencia de ejecución del código.

  2. Ahorre espacio en la memoria : el código de la función en línea se insertará directamente en cada punto de llamada y no se generará ninguna copia de la función en la memoria, lo que ahorrará espacio en el código.

3.3 Consideraciones para funciones en línea

  1. La complejidad de las funciones en línea : las funciones en línea suelen ser adecuadas para funciones cortas , ya que el cuerpo de la función es demasiado complejo para causar una sobrecarga de código, lo que reducirá el rendimiento. Los compiladores pueden rechazar la inserción de funciones complejas que están en línea .

  2. Decisión del compilador : el uso de palabras clave es solo una sugerenciainline para el compilador para la inserción y, en última instancia, depende del compilador decidir si usar la función como una función en línea. El compilador puede ignorar las palabras clave, especialmente para funciones demasiado complejas o recursivas.inline

  3. Inline no recomienda la separación de declaración y definición, lo que conducirá a errores de enlace.

  4. Evite el abuso de las funciones en línea : aunque las funciones en línea pueden aportar beneficios de rendimiento, no todas las funciones son adecuadas para la integración. El código de una función en línea se copiará en cada sitio de llamada. Si el cuerpo de la función es demasiado grande o se llama con frecuencia, provocará un exceso de código, lo que puede degradar el rendimiento.

Supongo que te gusta

Origin blog.csdn.net/weixin_57082854/article/details/132069044
Recomendado
Clasificación