Compartir tecnología

Lista de inicialización de constructores, miembros estáticos, amigos, clases internas [Clases y objetos (Parte 2)]

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

PD: El siguiente código se probó en el entorno VS2022, lo que no significa que todos los compiladores puedan pasarlo.
PD: Ninguno de los códigos de prueba muestra la declaración del archivo de encabezado stdio.h. Agréguelo usted mismo cuando lo use.

  

Insertar descripción de la imagen aquí

                                           Página de inicio de Blogger: LiUEEEEE
                                                columna C ++
                                              columna de lenguaje C
                                            Columna de estructura de datos
                                            Columna de algoritmo de clasificación
                                         Columna sobre temas clásicos de Niuke

1. Lista de inicialización del constructor.

1.1 Mirando hacia atrás al constructor


En mi blog anterior

          Construcción, destrucción, copia [Clases y Objetos (Parte 2)]
El constructor de la clase se menciona en. Tomando la clase de fecha como ejemplo, el método de inicialización es el siguiente:

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

Como se muestra en el código anterior, sin más estudios de C++, los usuarios generalmente pensarán que el código en el constructor es la inicialización de las variables miembro de la clase, pero el hecho es exactamente lo contrario. En C++, la declaración principal del constructor solo se inicializa. las variables miembro no se pueden llamar inicialización en el verdadero sentido, porque la inicialización solo se puede inicializar una vez, mientras que el constructor puede asignar valores a las variables miembro varias veces, por ejemplo:

	Date(int year, int month, int day)
	{
		_year = year;
		_year += 1;
	}
  • 1
  • 2
  • 3
  • 4
  • 5

1.2 Lista de inicialización


En este momento, se introduce la lista de inicialización en C++.
La lista de inicialización es una lista de miembros de datos que comienzan con ":" (dos puntos) y están separados por "," (coma). Cada variable miembro va seguida de un corchete, y el valor colocado entre corchetes es el valor inicializado, por ejemplo. :
	Date(int year, int month, int day)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
  • 1
  • 2
  • 3
  • 4
  • 5

hay que tener en cuenta es:

  1. Cada variable miembro solo puede aparecer una vez en la lista de inicialización (la inicialización solo se puede inicializar una vez)
  2. La clase contiene los siguientes miembros, que deben colocarse en la lista de inicialización para la inicialización:
    • Variables miembro de referencia
    • Variables miembro de tipo personalizado (y el tipo personalizado no tiene un constructor predeterminado: un constructor sin parámetros, un constructor totalmente predeterminado, un constructor generado automáticamente por el sistema)
    • variables miembro modificadas constantes

Las variables miembro personalizadas mencionadas anteriormente (sin el constructor predeterminado) significan que el constructor de la variable miembro personalizada definida es un constructor con parámetros, y los parámetros deben pasarse antes de que se pueda inicializar. Cuando el usuario implementa explícitamente el constructor, si es. La lista de inicialización no está escrita, el compilador la generará automáticamente para el usuario. Sin embargo, si la inicialización de variables miembro personalizadas requiere la participación de parámetros, el sistema no pasará los parámetros de forma predeterminada, lo que provocará la desinicialización. son para evitar que se produzca una situación de desinicialización para evitar problemas innecesarios en el uso posterior.

1.3 Consejos sobre la lista de inicialización


Al escribir la lista de inicialización, el orden de inicialización de las variables miembro debe ser coherente con el orden de declaración en la clase, porque el compilador inicializa las variables en secuencia de acuerdo con el orden de declaración. Si el usuario no escribe en el orden, provocará. problemas innecesarios, tales como:
class A
{
public:
	A(int n)
		:_a2(n)
		,_a1(_a2)
	{}
	void Print()
	{
		cout << "_a1 = " << _a1 << endl;
		cout << "_a2 = " << _a2 << endl;
	}
private:
	int _a1;
	int _a2;
};

int main()
{
	A aa(100);
	aa.Print();

	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Insertar descripción de la imagen aquí
Cuando se inicializa como se muestra en la figura anterior, se lograrán resultados que no sean consistentes con las expectativas, por lo que se deben evitar tales operaciones al usarlo.



2. palabra clave explícita


Para el constructor, también hay una función dedicada aconstructor de un solo parámetrooConstructor con múltiples parámetros pero sin valor predeterminado para el primer parámetroConversión de tipo implícita, por ejemplo:
class Date
{
public:
	Date(int year)
		: _year(year)
	{}
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
class Date
{
public:
	Date(int year, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

Al asignar pasando un valor, por ejemplo:

	Date date(2024);
  • 1

En el nivel del compilador, 2024 no se asigna directamente al objeto de clase creado, pero 2024 se convierte en un objeto de clase temporal mediante conversión implícita y luego se asigna al objeto de clase que debe inicializarse a través de dicho objeto. es necesario El objeto de clase inicializado es A y el objeto de clase temporal es B:

	Date A(2024);
	等价于
	Date A = B//B的值为2024
  • 1
  • 2
  • 3

Para evitar la conversión implícita, C++ creó la palabra clave explícita. Agregar explícita antes del constructor puede evitar que ocurra la conversión implícita, por ejemplo:
	explicit Date(int year)
		: _year(year)
	{}
  • 1
  • 2
  • 3




3. miembros estáticos

3.1 concepto de miembro estático


Los miembros de la clase declarados como estáticos se denominan miembros estáticos de la clase. Las variables miembro modificadas con estática se denominan variables miembro estáticas modificadas con estática se denominan funciones miembro estáticas. Las variables miembro estáticas deben inicializarse fuera de la clase, por ejemplo:
class Date
{
public:
	Date(int year, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
	static int _i;
};

int Date::_i = 1;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3.2 características de los miembros estáticos


  1. Los miembros estáticos son compartidos por todos los objetos de clase y no pertenecen a un objeto específico. Se almacenan en el área estática.
  2. Las variables miembro estáticas deben definirse fuera de la clase. La palabra clave estática no se agrega al definir, simplemente se declara en la clase.
  3. Se puede acceder a los miembros estáticos de la clase usando el nombre de la clase::miembro estático o miembro object.static
  4. Las funciones de miembros estáticos no tienen este puntero oculto y no pueden acceder a ningún miembro no estático.
  5. Los miembros estáticos también son miembros de la clase y están restringidos por calificadores de acceso público, protegido y privado.




4. Youyuan


Los amigos brindan una manera de romper con la encapsulación y, a veces, brindan comodidad. Sin embargo, los amigos aumentarán el acoplamiento y destruirán la encapsulación, por lo que los amigos no deben usarse más de una vez.

Los amigos se dividen en: funciones de amigos y clases de amigos.

4.1 Funciones de amigo


Una función amiga significa que cuando una función fuera de la clase necesita acceder a un miembro privado de la clase, se puede acceder a ella declarando esta función en la clase como una función amiga de la clase, por ejemplo:
class Date
{
	friend void Print(Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};
void Print(Date& d)
{
	cout << d._year << " " << d._month << " " << d._day <<endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • Las funciones amigas pueden acceder a miembros privados y protegidos de una clase, pero no a funciones miembro de la clase.
  • Las funciones amigas no se pueden modificar con const
  • Las funciones amigas se pueden declarar en cualquier lugar de una definición de clase y no están restringidas por calificadores de acceso a clase.
  • Una función puede ser una función amiga de múltiples clases.
  • El principio de llamar a funciones amigas es el mismo que el de las funciones ordinarias.

4.2 Clases de amigos


Cuando una clase quiere acceder a los miembros privados de otra clase, puede declarar esta clase como amiga en la clase a la que se debe acceder y luego puede acceder a sus miembros privados, por ejemplo:
class Time
{
	friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类
					   //中的私有成员变量
public:
	Time(int hour = 0, int minute = 0, int second = 0)
			: _hour(hour)
			, _minute(minute)
			, _second(second)
	{}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
			: _year(year)
			, _month(month)
			, _day(day)
	{}	
	void SetTimeOfDate(int hour, int minute, int second)
	{
		// 直接访问时间类私有的成员变量
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
	}
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • Las relaciones de amistad son unidireccionales y no conmutativas. Por ejemplo, en las clases Hora y Fecha mencionadas anteriormente, si declara la clase Fecha como su clase amiga en la clase Hora, puede acceder directamente a las variables miembro privadas de la clase Hora en la clase Fecha, pero desea acceder a las variables miembro privadas de la clase Fecha en la clase Hora No.
  • La relación de amigo no puede ser transitiva. Si C es amigo de B y B es amigo de A, no puede significar que C sea amigo de A.




5. Clase interna


C ++ admite la creación de otra clase dentro de una clase, que se denomina clase interna. La clase interna es una clase independiente. No pertenece a la clase externa y no se puede acceder a los miembros de la clase interna a través de los objetos de la clase externa. . La clase externa no tiene ningún acceso superior a la clase interna.
Y la clase interna es naturalmente amiga de la clase externa, es decir, la clase interna puede acceder a los miembros privados de la clase externa.

característica:

  1. Las clases internas se pueden definir como públicas, protegidas o privadas en clases externas.
  2. Tenga en cuenta que las clases internas pueden acceder directamente a miembros estáticos en clases externas sin requerir el nombre de objeto/clase de la clase externa.
  3. sizeof(clase externa)=clase externa, no tiene nada que ver con las clases internas.




6. Conclusión


Insertar descripción de la imagen aquí

  Muchas gracias por ver mi artículo original.
  Este artículo se utiliza principalmente para el aprendizaje personal y el intercambio de conocimientos. El viaje de aprendizaje es largo. Si hay algún error, gracias por corregirme.
  Si necesita citar, por favor indique la dirección.