Introducción a C++ (espacios de nombres, parámetros predeterminados, sobrecarga de funciones, referencias, funciones en línea)

introducción

El lenguaje C es un lenguaje estructurado y modular, adecuado para manejar programas de menor escala. Para problemas complejos y programas a gran escala que requieren un alto grado de abstracción y modelado, el lenguaje C no es adecuado. Para resolver la crisis del software, en la década de 1980, la industria informática propuso la idea de OOP (programación orientada a objetos: orientada a objetos), y surgieron los lenguajes de programación que soportan la programación orientada a objetos.
En 1982, el Dr. Bjarne Stroustrup introdujo y amplió el concepto de orientación a objetos sobre la base del lenguaje C e inventó un nuevo lenguaje de programación. Para expresar la relación de origen entre el lenguaje y el lenguaje C, se denomina C++. Por lo tanto: C++ se produce en base al lenguaje C. No solo puede llevar a cabo la programación procedimental del lenguaje C, sino también llevar a cabo la programación basada en objetos caracterizada por tipos de datos abstractos, y también puede llevar a cabo la programación orientada a objetos.

En el estudio previo del lenguaje C, creo que todos ya tienen una buena comprensión de la programación en lenguaje C, por lo que no repetiré la gramática básica. En este artículo, se presentarán algunos conocimientos nuevos que le permitirán comenzar con C++:

Entrada y salida C++

Lo primero que hay que entender es la entrada y salida de C++:

cout es un objeto de salida estándar , que se usa para escribir datos en el flujo de salida estándar (pantalla);
endl es un manipulador , el efecto de escribir endl es una nueva línea y los datos en el búfer se descargan en el dispositivo;
use el operador de salida < < puede imprimir información en la salida estándar:

std::cout << 表达式1 << 表达式2 << sts::endl;

cin es un objeto de entrada estándar , que se usa para leer datos del flujo de entrada estándar (teclado);
use el operador de entrada >> para leer datos de un flujo de entrada dado en un objeto dado:

std::cin >> 变量1 >> 变量2;

Al usar cin y cout para entrada y salida, el tipo de entrada o salida se puede identificar automáticamente y no se requiere la operación de tomar la dirección. En comparación con el lenguaje C, el formato de entrada y salida debe escribirse.

Al usar cin, cout y endl, los archivos de encabezado deben incluirse <iostream>y, dado que todas sus implementaciones están incluidas C++标准库命名空间std, es necesario introducir calificadores de ámbito de dominio o espacio de nombres al usarlos.

Espacios de nombres

A continuación, introduzca el conocimiento sobre los espacios de nombres:

En lenguaje C, a menudo se encuentra que las variables o funciones definidas por uno mismo entran en conflicto con las funciones definidas en la biblioteca, o las funciones definidas por uno mismo en el proyecto entran en conflicto con las funciones definidas por otros.La gente se aburre.
El propósito de usar espacios de nombres es localizar los nombres de los identificadores para evitar conflictos de nombres o contaminación de nombres.

concepto

Al definir un espacio de nombres, use la palabra clave espacio de nombres, seguida del nombre del espacio de nombres y luego defina los miembros (variables o funciones, etc.) en los siguientes {}:

namespace qqq
{
    
    
	int rand = 0;
	int max(int a = 0, int b = 0)
	{
    
    
		if (a > b)
		{
    
    
			return a;
		}
		return b;
	}
}

La variable rand y la función max definidas en el espacio de nombres qqq anterior son funciones implementadas en la biblioteca. Definir estos dos caracteres en el espacio de nombres qqq es equivalente a poner rand y max en el nombre en el ámbito espacial, en lugar de exponerlos al global. alcance, no habrá conflictos de nombres.

Los espacios de nombres se pueden anidar y se pueden definir varios espacios de nombres con el mismo nombre (que se combinarán en uno al compilar).

usar

Al usar variables miembro o funciones miembro en un espacio de nombres, hay tres formas:

use-scope-qualifier::use-a-member

Use calificadores de alcance: cuando use un miembro, cada vez que use un miembro en un espacio de nombres, debe escribir explícitamente 命名空间名::成员名:

//使用域作用限定符::使用某个成员
//省略头文件包含与命名空间qqq
int main()
{
    
    
	int a = qqq::rand;
	int b = 10;
	std::cout << qqq::max(a, b);
	return 0;
}

Use el uso del espacio de nombres para presentar todo el dominio del espacio de nombres

Cuando el nombre se usa using namespace 命名空间;para presentar todo el dominio del espacio de nombres, es equivalente a exponer todo el dominio del espacio de nombres al dominio global, y los miembros del espacio de nombres se vuelven globales. Se puede usar directamente cuando se usa:

//使用using namespace 引入整个命名空间域
//省略头文件包含与命名空间qqq
using namespace qqq;
using namespace std;
int main()
{
    
    
	int a = rand;
	int b = 10;
	cout << max(a, b);
	return 0;
}

Usar usando para presentar a un miembro

Aunque el método anterior es conveniente, exponer los miembros del espacio de nombres globalmente hace que el espacio de nombres pierda su significado original. Pero para algunas funciones de uso frecuente, la descripción explícita es demasiado engorrosa, por lo que podemos usar el using 命名空间名 :: 成员名;método para introducir un determinado miembro, lo que equivale a exponer este miembro globalmente, y se puede usar directamente cuando se use este miembro más adelante, pero no t Los miembros de todavía necesitan ser declarados explícitamente:

//使用using引入某个成员
//省略头文件包含与命名空间qqq
using qqq::max;
using std::cout;
int main()
{
    
    
	int a = qqq::rand;
	int b = 10;
	cout << max(a, b);
	return 0;
}

Los cin, cout y endl mencionados anteriormente están todos implementados en el espacio de nombres de la biblioteca estándar std. Por supuesto, puede expandir directamente la biblioteca estándar cuando usa: , o puede usarla cada vez, pero la forma más segura y conveniente es using namespace std;Introducir std::los Miembros de uso común: using std::cout; (por ejemplo, arriba).
Además de eso, todas las funciones de la biblioteca están en std.

parámetros predeterminados

Cuando es necesario inicializar un objeto, es mucho más conveniente establecer un valor predeterminado con parámetros predeterminados que #define en lenguaje C para definir una constante.

concepto

El parámetro predeterminado es especificar un valor predeterminado para el parámetro de la función al declarar o definir la función. Al llamar a esta función, si no se especifica ningún parámetro real, se adopta el valor predeterminado del parámetro formal; de lo contrario, se utiliza el parámetro real especificado.

#include<iostream>
void add(int a = 1, int b = 2)
{
    
    
	std::cout << a + b << std::endl;

}
int main()
{
    
    
	add();
	add(10);
	return 0;
}

inserte la descripción de la imagen aquí

Cabe señalar que: para evitar la diferencia entre el valor predeterminado de la definición y la declaración, la definición y la declaración de la función no pueden establecer el valor predeterminado al mismo tiempo.

Clasificación

Según si la lista de parámetros está completamente configurada en el valor predeterminado, se divide en predeterminado completo y semipredeterminado:

Todos los parámetros predeterminados significa que todos los parámetros en la lista de parámetros se establecen en valores predeterminados.
Al llamar a una función con todos los parámetros predeterminados, si se pasan los parámetros, a los parámetros reales se les asignarán valores a los parámetros formales en la lista de parámetros de izquierda a derecha, y las asignaciones no se pueden omitir:

#include<iostream>
void Func(int a = 1, int b = 2, int c = 3)
{
    
    
	std::cout << a << " " << b << " " << c << std::endl;
}
int main()
{
    
    
	//Func(10, , 30);错误调用
	Func();//正确调用
	Func(10, 20);
	return 0;
}

inserte la descripción de la imagen aquí

Un parámetro semipredeterminado es aquel en el que la lista de parámetros no establece todos los valores predeterminados.
Los parámetros semipredeterminados solo pueden dar valores predeterminados de derecha a izquierda; la cantidad de parámetros reales al llamar no puede ser menor que la cantidad de parámetros sin valores predeterminados, y se asignan a los parámetros reales a su vez de izquierda a derecha:

#include<iostream>
//void Func(int a = 1, int b, int c = 3){}错误定义
void Func(int a, int b = 2, int c = 3)
{
    
    
	std::cout << a << " " << b << " " << c;
}
int main()
{
    
    
	//Func();错误调用
	Func(10);//正确调用
	return 0;
}

inserte la descripción de la imagen aquí

sobrecarga de funciones

Al implementar funciones, a menudo hay algunas funciones que tienen funciones similares, pero los tipos de parámetros son diferentes. Si define varias funciones con diferentes nombres de función pero funciones similares, será un inconveniente llamar. Hay sobrecarga de funciones:

La sobrecarga de funciones es un caso especial de funciones. C++ permite declarar varias funciones del mismo nombre con funciones similares

Definición y llamada

Al definir la sobrecarga de funciones, el mismo nombre de función, diferente número de parámetros, diferentes tipos de parámetros y diferente orden de tipos de parámetros pueden constituir una sobrecarga:

int Func(int a, int b = 20)
{
    
    
	cout << 1 << endl;
	return 1;
}
int Func(double a, int b)//与第一个函数参数类型不同
{
    
    
	cout << 2 << endl;
	return 2;
}
int Func(int a, double b)//与第二个函数参数顺序不同
{
    
    
	cout << 3 << endl;
	return 3;
}
int Func(int a)//与第一个函数参数个数不同
{
    
    
	cout << 4 << endl;
	return 4;
}

Cabe señalar que cuando la lista de parámetros es la misma, la diferencia en el valor de retorno no constituye una sobrecarga :

//错误代码,会报错:无法重载仅按返回类型重载的函数
int Func(int a, int b = 20)
{
    
    
	cout << 1;
	return 1;
}
void Func(int a, int b)
{
    
    
	cout << 1;
}

inserte la descripción de la imagen aquí
Al llamar a una función sobrecargada, porque la función tiene parámetros predeterminados, por ejemplo, cuando solo se pasa un parámetro al llamar, no se sabe si llamar a una función sin valor predeterminado para el primer parámetro, o una función sobrecargada con solo uno parámetro formal u otras funciones que solo pueden pasar un parámetro. Por lo tanto, se debe tener especial cuidado para evitar la ambigüedad:

Func(10);//错误调用。对于传一个整型,第1个函数与第4个函数均可

inserte la descripción de la imagen aquí
En circunstancias normales, la función correspondiente se puede llamar de acuerdo con la lista de parámetros pasada:

Func(10, 30);
Func(1.1, 5);
Func(5, 1.1);

inserte la descripción de la imagen aquí

principio

Entonces, ¿por qué C++ admite la sobrecarga de funciones?

Como se introdujo en la parte avanzada del lenguaje C, antes de que el código que escribimos se convierta en un programa ejecutable, debe pasar por el proceso de precompilación, compilación, ensamblaje y enlace .
Al compilar, se genera una tabla de símbolos, y la tabla de símbolos incluye nombres y direcciones de símbolos. De acuerdo con las reglas de modificación de nombres de funciones, cada función diferente tendrá su propio símbolo único. Cuando aparezcan dos funciones con el mismo símbolo, se informará un error de compilación (es decir, una redefinición de símbolo).

Solo después de que el compilador del lenguaje C se modifique, se redefinirá la función cuyo nombre de símbolo sea el mismo que el nombre de la función; mientras que el nombre del símbolo modificado por el compilador de C++ contendrá información sobre el nombre de la función y la lista de parámetros . Los nombres de los símbolos de las funciones sobrecargadas son diferentes y no se redefinirán. Aunque los nombres de las funciones son los mismos cuando se llama, en realidad están llamando a funciones diferentes.
Sin embargo, dado que el tipo de valor devuelto no está incluido en las reglas de decoración, los nombres de símbolos de función con el mismo nombre de función y lista de parámetros pero con diferentes valores devueltos también son los mismos, por lo que no pueden constituir una sobrecarga.

cita

Una referencia es un alias , porque esencialmente usa el mismo espacio que la variable a la que se refiere, por lo que el valor de la variable a la que se refiere se puede cambiar a través de la variable de referencia y no se abre ningún espacio nuevo en la sintaxis.

definición

Agregue & después del tipo para definir una variable de referencia:类型& 引用变量名 = 引用实体;

int main()
{
    
    
	int a = 10;
	int& ra = a;
	int& rra = ra;
	cout << a << " " << ra << " " << rra << endl;
	rra = 20;
	cout << a << " " << ra << " " << rra << endl;
	return 0;
}

inserte la descripción de la imagen aquí

En el código anterior, se define la variable entera a, la variable de referencia ra es un alias de a, y rra es un alias de ra, es decir, rra también es un alias de a. Los tres nombres comparten un espacio, y cuando se cambia el valor de uno de los nombres, los valores de los otros dos también cambiarán.

requiere atención

Al definir variables de referencia, debe prestar atención a algunas cuestiones:

  1. Una referencia debe inicializarse cuando se define, es decir, debe quedar claro de quién es la referencia:
int& a;//错误代码,必须初始化引用
  1. Una entidad puede tener múltiples referencias, pero una variable de referencia solo puede referirse a una entidad:
int a = 10;
int b = 5;
int& ra = a;
int& rra = ra;
//int& ra = b; 错误代码,ra重定义
  1. Los permisos solo se pueden desplazar o alejar al citar, no acercar:

Cuando definimos una variable de referencia, podemos cambiar el valor de la entidad a través de esta referencia. Pero para una variable de entidad con un atributo constante, obviamente es muy peligroso darle un alias que pueda cambiar su contenido.
Por lo tanto, para variables con atributos constantes, solo se pueden inicializar referencias constantes (es decir, la autoridad de referencia no se puede ampliar):

const int a = 10;
//int& ra = a; 错误代码,权限放大
const int& ra = a; //正确代码

Por supuesto, si define una referencia constante para una no constante, es decir, la reducción o traducción de permisos, es posible:

int b = 5;
const int& rb = b;//正确代码,权限缩小
int& rrb = b;//正确代码,权限平移

No solo las variables modificadas por const, sino también el valor de retorno del valor pasado y la variable de conversión de tipo tienen propiedades constantes. Porque implícitamente copiarán una copia a una variable temporal al convertir, y luego asignarán un valor a la variable temporal, y esta variable temporal tiene atributos constantes.

  1. Un tipo de referencia debe ser el mismo que su tipo de entidad:
int c = 2;
//double& rc = c; 错误代码,引用与实体的类型不同

usar

Referencia como parámetro de tipo de retorno

En el pasado, para algunas implementaciones de funciones que requerían parámetros de retorno, solo podíamos usar punteros para pasar parámetros, lo que era problemático tanto para pasar parámetros como para invocarlos. Es conveniente utilizar referencias como parámetros de retorno, como esta función de intercambio:

//命名空间展开与头文件包含已省略
void Swap(int& a, int& b)
{
    
    
	int temp = b;
	b = a;
	a = temp;
}
int main()
{
    
    
	int a = 10;
	int b = 20;
	Swap(a, b);
	cout << a << " " << b;
	return 0;
}

inserte la descripción de la imagen aquí
No hay necesidad de tomar la dirección al pasar parámetros, y no hay necesidad de desreferenciar al intercambiar. También se ve muy claro y es más adecuado para los parámetros de retorno.

referencia como valor de retorno

El valor de retorno anterior solo se puede devolver por valor o por puntero. Al devolver por valor, hay un proceso de copia implícito, que afecta en gran medida la eficiencia para objetos grandes; devolver pasando un puntero no es conveniente para escribir. La devolución por referencia es eficiente e intuitiva:

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
Este tipo de código parece no tener ningún problema y también realiza la función de Agregar, pero hay un gran problema. Es decir, se devuelve una variable local por referencia. Este comportamiento es muy peligroso, porque el espacio de la variable local se devolverá al sistema operativo después de que finalice el ciclo de vida, y la referencia devuelta es un alias de datos indeterminados (si el entorno borra los datos, devolverá cualquier valor ).

Por lo tanto, debe prestar especial atención cuando utilice el retorno de referencia. El valor devuelto por referencia no debe destruirse cuando se sale del alcance . Puede devolver variables estáticas, etc.:

int& Add(int a, int b)
{
    
    
	static int c = a + b;
	return c;
}
int main()
{
    
    
	int a = 10;
	int b = 20;
	int c = Add(a, b);
	cout << c;
	return 0;
}

inserte la descripción de la imagen aquí

La diferencia entre referencia y puntero.

  1. La referencia define conceptualmente un alias de una variable, y un puntero almacena una dirección de variable;
  2. La referencia debe inicializarse cuando se define y no se requiere el puntero;
  3. Después de que la referencia hace referencia a una entidad durante la inicialización, ya no puede hacer referencia a otras entidades y el puntero puede apuntar a cualquier entidad del mismo tipo en cualquier momento;
  4. No hay referencias NULL, pero hay punteros NULL;
  5. El significado es diferente en sizeof: el resultado de referencia es el tamaño del tipo de referencia, pero el puntero es siempre el número de bytes ocupados por el espacio de direcciones (4 bytes en la plataforma de 32 bits);
  6. La adición autorreferencial significa que la entidad a la que se hace referencia aumenta en 1, y el autoincremento del puntero significa que el puntero desplaza el tamaño de un tipo hacia atrás;
  7. Hay punteros de varios niveles, pero no referencias de varios niveles;
  8. Hay diferentes formas de acceder a las entidades, el puntero debe ser desreferenciado explícitamente y el compilador de referencia lo maneja solo;
  9. Las referencias son relativamente más seguras de usar que los punteros;

Cabe señalar que aunque la referencia no abre un nuevo espacio en la sintaxis, es consistente con el puntero en la lógica subyacente y también necesita abrir espacio para almacenar la dirección.

función en línea

En la parte del lenguaje C, para funciones simples y llamadas con frecuencia, podemos usar funciones de macro para reemplazar macros en la etapa de precompilación y ahorrar tiempo y espacio para que las funciones abran marcos de pila para mejorar la eficiencia. Por ejemplo, la macro función AÑADIR:

#define ADD(a, b) ((a)+(b))

Dado que la función macro es un reemplazo directo en lugar de pasar parámetros, no hay problema con la lógica de la función macro y el método de escritura es obviamente un poco engorroso.

La función en línea puede resolver tales problemas: la función
modificada inlinese llama función en línea, y el compilador de C++ la expandirá en el lugar donde se llama a la función en línea durante la compilación.

inline int Add(int a, int b)
{
    
    
	return a + b;
}

hay que tener en cuenta es:

  1. En línea es una forma de intercambiar espacio por tiempo.Si el compilador trata la función como una función en línea, reemplazará la llamada de función con el cuerpo de la función durante la fase de compilación. Defecto: puede hacer que el archivo de destino sea más grande; Ventaja: menos sobrecarga de llamadas, mejora la eficiencia de ejecución del programa
  2. Inline es solo una sugerencia para el compilador. Diferentes compiladores pueden tener diferentes mecanismos de implementación en línea. La sugerencia general es usar la modificación en línea para funciones que son de pequeña escala, no recursivas y llamadas con frecuencia, de lo contrario, el compilador ignorará la función en línea. .
  3. La declaración de funciones y variables en línea no debe separarse (archivos separados). Dado que la función en línea es un reemplazo directo sin una dirección de función, si está separada, no se puede reemplazar y no se puede llamar de acuerdo con el puntero de la función, y se informará un error;

Resumir

Hasta ahora, he introducido algunos conocimientos sobre la introducción de C ++, y
continuaré actualizando el conocimiento de C ++ en el futuro. Le invitamos a seguir prestando atención.

Si este artículo es útil para usted, espero que se conecte con un solo clic.

El camino hacia C++ acaba de comenzar, ¡trabajemos juntos!

Supongo que te gusta

Origin blog.csdn.net/weixin_73450183/article/details/130460140
Recomendado
Clasificación