Conceptos básicos de la entrada de C ++ (¡explicación detallada de 10,000 palabras!)

prefacio

  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. Con el fin de solucionar 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 los lenguajes de programación que soportan la programación orientada a objetos surgieron como los tiempos lo requieren.
  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.

escenario contenido
C con clases Clases y clases derivadas, miembros públicos y privados, construcción y destrucción de clases, amigos, funciones en línea, sobrecarga de operadores de asignación, etc.
C++ 1.0 Agregue conceptos de funciones virtuales, sobrecarga de funciones y operadores, referencias, constantes, etc.
C++2.0 Compatibilidad más completa con nuevos miembros de protección orientados a objetos, herencia múltiple, inicialización de objetos, clases abstractas, miembros estáticos y funciones de miembros constantes
C++3.0 Mejoras adicionales, introducción de plantillas, resolución del problema de ambigüedad causado por la herencia múltiple y tratamiento de la construcción y destrucción correspondientes.
C++98 La primera versión del estándar C++, compatible con la mayoría de los compiladores, ha sido reconocida por la Organización Internacional para la Estandarización (ISO) y la Asociación Estadounidense de Estándares. Reescribe la biblioteca estándar de C++ en forma de plantilla e introduce STL (Biblioteca de plantillas estándar)
C++03 La segunda versión del estándar C++ no tiene cambios importantes en las características del lenguaje, principalmente: revisión de errores, reducción de heterogeneidad
C++05 El Comité de Estándares de C++ publicó un informe de conteo (Informe Técnico, TR1), oficialmente renombrado como C++0x, es decir, está previsto que se publique en algún momento de la primera década de este siglo.
C++11 Se han agregado muchas funciones para hacer que C++ se asemeje más a un nuevo lenguaje, como: expresiones regulares, bucles for basados ​​en rangos, palabras clave automáticas, nuevos contenedores, inicialización de listas, bibliotecas de subprocesos estándar, etc.
C++14 La extensión a C++11 es principalmente para corregir errores y mejoras en C++11, tales como: expresiones lambda genéricas, deducción de tipo de valor de retorno automático, constantes literales binarias, etc.
C++17 Realizó algunas pequeñas mejoras en C++ 11, agregando 19 características nuevas, como: la información de texto static_assert() es opcional, la expresión Fold se usa para plantillas variables, inicializadores en declaraciones if y switch, etc.
C++20 El lanzamiento más grande desde C++ 11, que presenta muchas características nuevas, como: módulos (Módulos), corrutinas (Corrutinas), rangos (Rangos), conceptos (Restricciones) y otras características importantes, así como características existentes Actualizaciones: por ejemplo , Lambda admite plantillas, alcance para la inicialización de soportes, etc.
C++23 formulando

1. Palabras clave de C++

  Estas son todas las palabras clave de C++, cada una de las cuales tiene un significado especial, aquí una por una es problemática y difícil de entender, así que la explicaré en detalle cuando la encuentre más adelante.
inserte la descripción de la imagen aquí

2. Espacio de nombres

  En C/C++, hay una gran cantidad de variables, funciones y clases que se aprenderán más adelante. Los nombres de estas variables, funciones y clases existirán en el ámbito global, lo que puede causar muchos conflictos. El propósito de usar el espacio de nombres es localizar el nombre del identificador para evitar conflictos de nombres o contaminación de nombres.La aparición de la palabra clave del espacio de nombres está dirigida a este tipo de problema.
  Por ejemplo, hay una función rand() en <stdlib.h>, que es una función utilizada para generar números aleatorios.
inserte la descripción de la imagen aquí
  En este punto, podemos ver que puede ejecutarse normalmente sin el archivo de encabezado <stdlib.h>, así que veamos qué sucede después de incluir el archivo de encabezado.
inserte la descripción de la imagen aquí
  Descubrimos que la compilación falló. Esto se debe a que el contenido en el archivo de encabezado se expandirá durante la compilación, y la función rand() tendrá el mismo nombre que la variable global rand que definimos, por lo que se redefinirá, por lo que el espacio de nombres se llama Space se crea en consecuencia, y su función es evitar que esto suceda.
  Un espacio de nombres es usar la palabra clave de espacio de nombres para agregar cualquier nombre y llaves. Pero puede observar que escribí WY : : rand en la línea de salida, lo que significa generar el rand en el espacio de nombres WY en lugar de usar el rand en el archivo de encabezado.
inserte la descripción de la imagen aquí
  Un espacio de nombres es como una pared invisible que separa las variables con el mismo nombre en diferentes espacios.Puede encontrar las variables en el espacio que necesita. Pero, ¿qué pasa con las variables con el mismo nombre en un espacio de nombres? Los creadores de C++ ya pensaron en este problema, es decir, los espacios de nombres también se pueden abrir en espacios de nombres, comúnmente conocidos como muñecos anidados.
inserte la descripción de la imagen aquí
  Los espacios de nombres pueden definir variables, funciones y tipos. Sin embargo, debe tenerse en cuenta que al definir un tipo de estructura, se debe acceder a ella al accederdetrás de la estructuraescrito. al mismo tiempoLos espacios de nombres con el mismo nombre están permitidos en el mismo proyecto, y el compilador los fusionará automáticamente al compilar

int rand = 0;//全局变量
namespace WY
{
    
    
	int rand = 1;

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

	struct Node
	{
    
    
		int data;
		int* next;
	};
}
int main()
{
    
    
  //域作用限定符
	printf("%d", rand);
	printf("%d", WY::rand);
	printf("%d", WY::Add(1,2));
	struct WY::Node node;

	return 0;
}

  En el pasado, la voz C todavía se usaba para simular algunos entornos, entonces, ¿cómo es C++ en sí mismo? C++ tiene su propio espacio de nombres y archivos de encabezado.

//C++标准库的命名空间,将标准库的定义与实现都放入了这个命名空间中
#include<iostream>
using namespace std;
int main()
{
    
    
	cout << "Wang You" << endl;
}

  Pero esta forma de escribir expande todo el contenido en el espacio de nombres, lo cual es muy fácil de causar problemas de redefinición.Por ejemplo, cuando escribe un proyecto con otros, usa el mismo nombre de variable, y el resultado es cuando lo ejecutan juntos en al final Todos expanden sus propios espacios de nombres, entonces, ¿no habría una redefinición? Por lo tanto, esta forma de escribirNo es aconsejable cuando se trabaja con otros, pero está bien en su propia práctica diaria.Después de todo, los nombres de las variables se controlan por sí mismos, lo que puede evitar esta situación.
  Al mismo tiempo, la expansión también se puede expandir total o parcialmente. Por ejemplo, si la función Agregar debe usarse con frecuencia, se puede expandir parcialmente, de modo que no es necesario agregar un calificador de alcance ( : : ) antes de cada uso.

//全部展开
using namespace WY;

//部分展开
using WY::Add;

3. Entrada y salida de C++

  De hecho, fue escrito una vez arriba, por favor vea:

#include<iostream>
using namespace std;
int main()
{
    
    
	int a;
	cin >> a;
	cout << "Wang You" << endl;
	return 0;
}

cout se usa para la salida, que tiene la misma función que printf en lenguaje C, y el otro es cin, que tiene la misma función que scanf.

En comparación con el lenguaje C, cabe señalar que

  1. Al usar el objeto de salida estándar cout (consola) y el objeto de entrada estándar cin (teclado), debe incluir el archivo de encabezado <iostream> y usar std por uso de espacio de nombres.
  2. cout y cin son objetos de flujo global, y endl es un símbolo especial de C++ que representa la salida de nueva línea.Todos están incluidos en el archivo de encabezado <iostream>.
  3. <<es el operador de inserción de flujo,>>es el operador de extracción de flujo.
  4. Es más conveniente usar la entrada y salida de C++, y no es necesario controlar manualmente el formato como la entrada y salida de printf/scanf. La entrada y salida de C++ puede identificar automáticamente el tipo de variable.
  5. De hecho, cout y cin son objetos de tipo ostream e istream respectivamente.>> y << también implican sobrecarga de operadores y otros conocimientos, que se explicarán más adelante, así que aquí hay solo un estudio simple de su uso.

Cuando se expande el uso de namespace std, la biblioteca estándar está completamente expuesta.Si definimos un tipo/objeto/función con el mismo nombre que la biblioteca, habrá conflictos. Este problema rara vez ocurre en la práctica diaria, pero es fácil que ocurra cuando hay muchos códigos y gran escala en el desarrollo de proyectos. Por lo tanto, se recomienda usarlo en el desarrollo de proyectos, especificando el espacio de nombres + usando std::cout para expandir tipos/objetos de biblioteca comunes cuando se usa como std::cout.

4. Parámetros predeterminados

  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.
inserte la descripción de la imagen aquí
  Generalmente, al llamar a una función, le pasaremos parámetros. El significado de los parámetros predeterminados es que cuando no pasa parámetros a la función, automáticamente pasará los parámetros predeterminados que estableció de forma predeterminada (int a = 0).

4.1 Ministerio Integral

void fun(int a = 10, int b = 20, int c = 30)
{
    
    
	cout << a << " ";
	cout << b << " ";
	cout << c << " ";
	cout << endl;
}

inserte la descripción de la imagen aquí
  De esto también podemos verLos parámetros predeterminados se deben dar de derecha a izquierda, por lo que los parámetros que damos son de izquierda a derecha, los datos de la izquierda pueden ser mostrados y pasados ​​por nosotros, y los datos de la derecha pueden usar los parámetros predeterminados.

4.2 Semi-defecto

  Entonces echemos un vistazo a los semi-predeterminados nuevamente, como su nombre lo indica, solo algunos de ellos tienen valores predeterminados.

void fun(int a,int b,int c = 30)
{
    
    
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

inserte la descripción de la imagen aquí

Aviso:

  1. Los parámetros semipredeterminados se deben dar secuencialmente de derecha a izquierda y no se pueden dar alternativamente.
  2. Los parámetros predeterminados no pueden aparecer tanto en la declaración como en la definición de la función.
  3. El valor predeterminado debe ser una constante o una variable global
  4. El lenguaje C no es compatible (el compilador no es compatible)

  Aparecen diferentes declaraciones y definiciones al mismo tiempo porque si los parámetros predeterminados dados en la definición son diferentes de los parámetros predeterminados dados en la declaración, el compilador no puede distinguirlos, por lo que los parámetros predeterminados (parámetros predeterminados) se dan todos en la definición.

5. Sobrecarga de funciones

  La sobrecarga de funciones es un caso especial de funciones. C++ permite declarar varias funciones del mismo nombre con funciones similares en el mismo ámbito. El parámetro formal enumera estas funciones con el mismo nombre (Número de parámetrosotipootipo de orden) son diferentes y, a menudo, se utilizan para tratar el problema de implementar funciones similares con diferentes tipos de datos.
inserte la descripción de la imagen aquí
  El sistema emparejará y llamará automáticamente a la función más coincidente según sus tipos de parámetros, incluso si los nombres de función son los mismos.

Pero debe satisfacer la lista de parámetros formales (Número de parámetrosotipootipo de orden) es diferente, solo una de estas tres condiciones es aceptable.

Entonces, ¿cómo el compilador nota la diferencia?

  De hecho, cuando se llama a esta función dentro del editor, se encuentra agregando el nombre y la dirección de la función. El nombre de la función interna de cada función al vincular, el compilador se basará en el nombre de la función (divertido) que escribiste. Luego agrega algunos símbolos. para modificarlo según sus parámetros. Por ejemplo, en VS2019, los nombres de función de las dos funciones durante el proceso de vinculación son los que se muestran en la figura, uno es HN y el otro es NH. Entonces el compilador los distinguirá con precisión.
inserte la descripción de la imagen aquí
  En el lenguaje C, la modificación del nombre de la función interna es la misma, por lo que el compilador no puede distinguir. A través de esto, puedo entender por qué el lenguaje C no puede soportar la sobrecarga, porque no hay forma de distinguir funciones con el mismo nombre. C ++ se distingue por las reglas de modificación de funciones. Siempre que los parámetros sean diferentes, los nombres modificados son diferentes y se admite la sobrecarga.

Si los nombres de las funciones y los parámetros de dos funciones son los mismos, pero los valores devueltos son diferentes, no constituye una sobrecarga, porque el compilador no tiene forma de distinguir cuando llama.

6. Cita

  Una referencia no es una nueva definición de una variable, sino un alias (es decir, un apodo) para una variable existente. El compilador no abrirá espacio de memoria para la variable de referencia y comparte el mismo espacio de memoria con la variable que se refiere a.
inserte la descripción de la imagen aquí
  Por ejemplo, el nombre de un espacio es a, y le das un apodo que se llama b. Aunque el nombre es diferente, es el mismo espacio.
inserte la descripción de la imagen aquí
  Parecen dos nombres, pero en realidad son el mismo espacio, uno es próspero y el otro está dañado, tú eres yo y yo soy tu relación. hay que ser consciente de esEl tipo de referencia debe ser del mismo tipo que la entidad referenciada

6.1 Características de las referencias

  1. Las referencias deben inicializarse cuando se definen
  2. Una variable puede tener varias referencias.
  3. Una vez que una referencia se refiere a una entidad, no puede referirse a otra entidad
int main()
{
    
    
	int a = 10;
	int& b;
	//正确写法:int& b = a;
	return 0;
}

  No es aceptable escribir de esta manera, porque está creando un alias de una variable existente y no puede existir como el apodo de otra persona sin inicialización.

int main()
{
    
    
	int a = 10;
	int& ra = a;
	int& raa = a;
	return 0;
}

  Es posible escribir de esta manera, una variable puede tener muchos apodos. Pero un apodo solo puede ser usado por una persona, ¿no sería un desastre si cualquiera pudiera usarlo?Una vez que una referencia se refiere a una entidad, no puede referirse a otra entidad.
  Para las variables modificadas por const, significa que solo se pueden leer pero no escribir, por lo tanto, también se debe agregar const al alias de las variables const, para que no se pueda modificar agregando un apodo.

void test()
{
    
    
    const int a = 10;
    int& ra = a;   // 该语句编译时会出错,a为常量
    //正确写法:const int& ra = a;
    
    const int& ra = a;
    int& b = 10; // 该语句编译时会出错,b为常量
    //正确写法:const int& b = 10;
    
    const int& b = 10;
    double d = 12.34;
    int& rd = d; // 该语句编译时会出错,类型不同
    //正确写法:const int& rd = d;
}

  Y para el último tipo que es diferente, ¿por qué agregar const? Esto se debe a que primero se generará un int temporal al realizar una conversión de tipo implícita.constante, primero convierta el valor de d de tipo doble a tipo int y asígnelo a una variable temporal, y luego asigne un alias a la variable temporal. Debido a que es una constante y no se puede modificar, también es necesario agregar const al tomar un alias.

6.2 Escenarios de uso referenciados

  Como argumento a una función para que se puedan intercambiar los valores de dos variables sin necesidad de punteros.

void Swap(int& left, int& right)
{
    
    
   int temp = left;
   left = right;
   right = temp;
}

  como valor de retorno. La devolución por referencia será más rápida, porque el alias de la variable se devuelve directamente. En una función normal, la función se destruye después de ser llamada, por lo que primero da el valor de retorno a una variable temporal y la variable temporal se devuelve a la función principal. Por lo tanto, debe tenerse en cuenta que,Cuando se devuelve una referencia, debe devolver una variable estática o una variable en el montón

int& Count()
{
    
    
   static int n = 0;
   n++;
   // ...
   return n;
}

Los valores se utilizan como parámetros o tipos de valores devueltos.Durante el paso y la devolución de parámetros, la función no pasa directamente los parámetros reales ni devuelve la variable en sí, sino que pasa los parámetros reales o devuelve una copia temporal de la variable, por lo que los valores se utilizan como parámetros O el tipo de valor de retorno es muy ineficiente, especialmente cuando el tipo de parámetro o valor de retorno es muy grande, la eficiencia es aún menor.

6.3 Referencias y punteros

  Los punteros y las referencias se usan de manera diferente, pero la implementación subyacente es en realidad la misma.Veamos un fragmento de código de este tipo.

#include<iostream>
using namespace std;
int main()
{
    
    
	int a = 10;
	int* pa = &a;
	int& ra = a;

	++(*pa);
	++ra;
	return 0;
}

  Aunque no entiendo muy bien el ensamblado, no impide que veamos que para la aritmética de punteros y la aritmética de referencias, el compilador implementa el mismo ensamblado en la capa inferior, por lo que podemos saber que la referencia en realidad se implementa a través de punteros.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

  1. Una referencia define conceptualmente un alias para una variable y un puntero almacena la dirección de una variable.
  2. Las referencias deben inicializarse cuando se definen, no se requieren punteros

  3. Después de que la referencia hace referencia a una entidad durante la inicialización, 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. El autoincremento de la referencia significa que la entidad a la que se hace referencia aumenta en 1, y el autoincremento del puntero significa que el puntero compensa el tamaño de un tipo hacia atrás.
  7. Punteros de varios niveles, pero sin 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.

7. Funciones en línea

  Una función modificada con en línea se denomina función en línea. Al compilar, el compilador de C++ la expandirá en el lugar donde se llama a la función en línea. No hay sobrecarga para llamar a la función para construir un marco de pila. Las funciones en línea mejoran la eficiencia del programa operación.

inline void Fun(int& a, int& b)
{
    
    
	int tmp = a;
	a = b;
	b = tmp;
}

int main()
{
    
    
	int a = 10, b = 20;
	Fun(a, b);
	return 0;
}
int main()
{
    
    
	int a = 10, b = 20;
	int tmp = a;
	a = b;
	b = tmp;
	return 0;
}

  La función de la función en línea es convertir el código anterior en el siguiente código, es decir, no llamar a la función, sino expandir el código de función en su lugar. ¿Encontraste que esto es similar a lo que está en el lenguaje C? Sí, esmacro

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

  Esto es para implementar una función de suma con una macro. Sabemos que la macro se reemplaza directamente en la posición correspondiente, pero sabemos que el operador tiene una prioridad. El reemplazo directo puede causar una prioridad incorrecta del operador y causar errores.

Desventajas de las macros:

  1. Inconveniente para depurar macros. (Porque se reemplaza la fase de precompilación)
  2. Conduce a una mala legibilidad del código, poca capacidad de mantenimiento y fácil uso indebido.
  3. No hay comprobaciones de seguridad de tipo.

Ventajas de las macros

  1. No hay un control estricto de tipo.
  2. Para llamar con frecuencia a funciones pequeñas, no es necesario crear un marco de pila para mejorar el rendimiento.

  Entonces, para evitar este tipo de error, C ++ ha agregado la función en línea para resolver este problema. No necesita escribir deliberadamente muchos paréntesis para garantizar el orden de uso correcto de los operadores.

7.1 Características

  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 a la función con el cuerpo de la función durante la fase de compilación. Defecto: puede hacer que el archivo del objeto sea más grande. Ventaja: menos llamada gastos generales, mejorar la eficiencia de la operació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: hacer la función más pequeña (es decir, la función no es muy larga, no hay una declaración exacta, depende de la implementación interna del compilador), no se deben insertar funciones que sean recursivas y llamadas con frecuencia, de lo contrario, el compilador ignorará la función en línea. Sugerencias para en línea en la quinta edición de "C++prime":La inserción es solo una solicitud al compilador, que puede ser ignorada por el compilador
  3. Inline no recomienda la separación de declaración y definición, lo que conducirá a errores de enlace. Debido a que se expande en línea, no hay una dirección de función y no se encontrará el enlace.

8. palabra clave automática

  El significado de auto en C/C++ temprano es: la variable modificada con auto es una variable local con memoria automática, pero desafortunadamente nadie la ha estado usando. ¿Puedes pensar por qué?
  En C++11, el comité estándar le dio a auto un nuevo significado: auto ya no es un indicador de tipo de almacenamiento, sino un nuevo indicador de tipo para instruir al compilador, y las variables declaradas por auto deben ser compiladas por el compilador derivadas de periodo de tiempo.
inserte la descripción de la imagen aquí
  Es decir, auto eliminará automáticamente el tipo de variable, lo cual es conveniente para algunos tipos de variables que son relativamente largos y se encontrarán más adelante.

El rol de typeid().name() es identificar el tipo de una variable.

Cuando se usa auto para definir una variable, debe inicializarse.En la etapa de compilación, el compilador necesita deducir el tipo real de auto de acuerdo con la expresión de inicialización. Por lo tanto, auto no es una declaración de "tipo", sino un "marcador de posición" cuando se declara el tipo. El compilador reemplazará auto con el tipo real de la variable durante la compilación.

8.1 Precauciones

  Cuando usa auto para declarar un tipo de puntero, no hay diferencia entre usar auto y auto*, pero cuando usa auto para declarar un tipo de referencia, debe agregar &.
inserte la descripción de la imagen aquí
  Al declarar varias variables en la misma línea, estas variables deben ser del mismo tipo, de lo contrario, el compilador informará un error, porque el compilador en realidad solo deduce el primer tipo y luego define otras variables con el tipo deducido.

void test_auto()
{
    
    
    auto a = 1, b = 2; 
    auto c = 3, d = 4.0;  
    // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}
  1. auto no se puede utilizar como un parámetro de función.
  2. auto no se puede usar directamente para declarar matrices.
  3. Para evitar confusiones con auto en C++98, C++11 solo retiene el uso de auto como indicador de tipo.
  4. La ventaja más común de auto en la práctica es usarlo junto con el nuevo bucle for proporcionado por C++ 11, que se mencionará más adelante, y las expresiones lambda.

9. Bucle for basado en rango

  Por lo general, iteramos sobre una matriz como esta:

int main()
{
    
    
	int a[5] = {
    
     0,1,2,3,4 };
	for(int i = 0; i < 5; i++)
	{
    
    
		cout << a[i] << " ";
	}
	return 0;
}

  Para una colección de rangos, es redundante y, a veces, propenso a errores que el programador especifique el rango del ciclo. Por lo tanto, los bucles for basados ​​en rangos se introdujeron en C++11. Los paréntesis después del ciclo for se dividen en dos partes por el signo ":": la primera parte es la variable utilizada para la iteración en el rango y la segunda parte representa el rango que se va a iterar.
inserte la descripción de la imagen aquí
  El proceso real es sacar un número en arr y ponerlo en e, generarlo y luego continuar para obtener el segundo número...

9.1 Condiciones de uso

  1. Se debe determinar el rango de la iteración del bucle for.
      Para una matriz, es el rango del primer elemento y el último elemento de la matriz; para una clase, se deben proporcionar los métodos de comienzo y fin, y comienzo y fin son los rango de la iteración del bucle for.
void test_for(int arr[])
{
    
    
    for(auto& e : arr)
        cout<< e <<endl;
}

  Escribir de esta manera es problemático, porque el alcance de for es indeterminado.
2. El objeto iterado debe implementar las operaciones de ++ y ==, y esto es para clases.

10. Control de puntero nullptr

  En una buena práctica de programación C/C++, es mejor dar a la variable un valor inicial adecuado al declarar una variable, de lo contrario, pueden ocurrir errores inesperados, como punteros no inicializados. Si un puntero no tiene un punto legal, básicamente lo inicializamos de la siguiente manera:

void test_ptr()
{
    
    
	int* p1 = NULL;
	int* p2 = 0;
	//……	
}

  NULL es en realidad una macro. En el archivo de encabezado C tradicional (stddef.h), puede ver el siguiente código:

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

  Como puede ver, NULL puede definirse como la constante literal 0, o como una constante de un puntero sin tipo (void*). No importa qué tipo de definición se adopte, inevitablemente se encontrarán algunos problemas al usar punteros de valores nulos, como:

void f(int)
{
    
    
 	cout<<"f(int)"<<endl;
}
void f(int*)
{
    
    
 	cout<<"f(int*)"<<endl;
}
int main()
{
    
    
 	f(0);
 	f(NULL);
 	f((int*)NULL);
 	return 0;
}

inserte la descripción de la imagen aquí

  La intención original del programa es llamar a la versión de puntero de la función f(int*) a través de f(NULL), pero dado que NULL se define como 0, es contrario a la intención original del programa.
  En C++98, la constante literal 0 puede ser un número entero o una constante de puntero sin tipo (void*), pero el compilador la trata como una constante entera de manera predeterminada. (vacío *)0.
  Por lo tanto, en C++, esta situación se distingue y nullptr se usa específicamente para referirse a punteros.

10.1 Precauciones

  1. Cuando se usa nullptr para representar el valor nulo del puntero, no es necesario incluir el archivo de encabezado, porque nullptr se introdujo como una nueva palabra clave en C++11.
  2. En C++11, sizeof(nullptr) y sizeof((void*)0) ocupan la misma cantidad de bytes.
  3. Para mejorar la solidez del código, se recomienda utilizar nullptr al representar el valor nulo del puntero más adelante.

11. Resumen

  Al aprender C++ por primera vez, hay muchos lugares para memorizar. No es difícil pero hay muchos detalles. Se recomienda que organice algunas notas para ayudarlo a revisar en el futuro.
  La cantidad de palabras en este artículo es aceptable, y los principiantes en C++ todavía están un poco cansados ​​(suspiro), pero es mucho mejor que antes (placer). Si encuentras algo mal, puedes señalarlo en un mensaje privado o en el área de comentarios (pidiendo consejo con humildad, ansioso por la ayuda del jefe). Continuaré estudiando C++ en profundidad y espero progresar junto con todos, así que este es el final de este número, ¡nos vemos la próxima vez! ! Si te sientes bien, ¡puedes hacer clic en Me gusta para mostrar tu aliento! !

Supongo que te gusta

Origin blog.csdn.net/qq_62321047/article/details/132257687
Recomendado
Clasificación