Notas de estudio de C ++ once: el uso de clases de combinación y declaraciones de referencia hacia adelante

Para las clases, los artículos anteriores describieron brevemente qué es una clase, su constructor y el rol de su constructor de copia. Los enlaces relacionados del artículo anterior son los siguientes:
definición de clase e inicialización
copia constructor y destructor
Luego, lo siguiente presentará clases compuestas, ¿qué es una clase compuesta? ¿Cuál es el papel de la clase combinada? Por lo general, cuando definimos un objeto de una clase, los tipos de miembros de la clase son en realidad tipos de datos básicos, como int, float, double ... De hecho, los miembros de la clase pueden ser no solo tipos de datos básicos, sino también tipos de datos personalizados. Es decir, el tipo de datos también puede ser el objeto de la clase , por lo que si se define una clase compuesta, el orden en el que se construye la clase es muy importante. Cuando utilice el constructor mencionado anteriormente para inicializar una clase, siga la siguiente secuencia de construcción:
1. Cuando el tipo de miembro de la clase es un objeto de la clase, primero inicialice la estructura de los datos del miembro de la clase. Los miembros de la clase se construyen en el orden de definición, primero define primero para construir
2. El constructor se está construyendo a sí mismo.
Aquí hay un ejemplo para ilustrar el problema, primero definimos una clase puntual

class point 
{
    
    
private:
	int x,  y;
public:
	int getx() {
    
     return x; }
	int gety() {
    
     return y; }
	point(int xx = 0, int yy = 0) :x(xx), y(yy) {
    
     cout << "calling point init constructor" << endl; }//构造函数
	point(const point & p1);//复制构造函数


};

Siempre que se utiliza el constructor de inicialización, se emite la declaración de depuración correspondiente. Esta clase también contiene el entero xy. El
constructor de copia se define de la siguiente manera

point::point(const point &p1) {
    
    
	cout << "calling point copy constructor" << endl;
	x = p1.x;
	y = p1.y;
}

Puede ver que el constructor de copias de la clase de puntos copia los miembros correspondientes xy a otro miembro uno por uno.
Lo siguiente define una clase de línea, la línea contiene la clase de punto y la línea correspondiente se define de la siguiente manera

class line {
    
    
private:
	double len;
	//私有成员为point类
	point p1, p2;
public:
	double getline() {
    
     return len; }
	line(point xp1, point xp2);//构造函数
	line(const line  &p11);//复制构造函数

};

Hemos visto el uso de clases compuestas, usando la clase de punto como miembro de datos en la línea, echemos un vistazo al contenido del constructor.

line::line(point xp1, point xp2):p1(xp1),p2(xp2)
{
    
    
	cout << "calling line init construct" << endl;
	double x = static_cast<double>(p1.getx() - p2.getx());
	double y = static_cast<double>(p1.gety() - p2.gety());
	len = sqrt(x*x + y*y);

}

Se puede ver que se usa una lista de inicialización simple para inicializar el punto primero, calcular la distancia en base a los datos de dos puntos y asignar el valor a len.
Eche un vistazo al constructor de copias de point

line::line(const line &p11 ) 
{
    
    
	cout << "calling line copy construct" << endl;
	p1 = p11.p1;
	p2 = p11.p2;
	len = p11.len;
}

Lo anterior son todos los datos y constructores de línea y punto A continuación llamamos y observamos la secuencia de las siguientes construcciones en la función principal. el código se muestra a continuación:

# include <iostream>
# include <cmath>
using namespace std;
//类的组合,实际上我们在定义类的成员时通常会定义基础数据类型,实际上类的成员也可以是类的对象。
//类的组合描述的就是一个类内嵌其他类作为成员的情况。他们之间的关系是一种包含于被包含的关系
//值得注意的是类的构造顺序。
class point 
{
    
    
private:
	int x,  y;
public:
	int getx() {
    
     return x; }
	int gety() {
    
     return y; }
	point(int xx = 0, int yy = 0) :x(xx), y(yy) {
    
     cout << "calling point init constructor" << endl; }//构造函数
	point(const point & p1);//复制构造函数


};
point::point(const point &p1) {
    
    
	cout << "calling point copy constructor" << endl;
	x = p1.x;
	y = p1.y;
}
//类的组合
class line {
    
    
private:
	double len;
	//私有成员为point类
	point p1, p2;
public:
	double getline() {
    
     return len; }
	line(point xp1, point xp2);//构造函数
	line(const line  &p11);//复制构造函数

};
//组合类的构造函数
line::line(point xp1, point xp2):p1(xp1),p2(xp2)
{
    
    
	cout << "calling line init construct" << endl;
	double x = static_cast<double>(p1.getx() - p2.getx());
	double y = static_cast<double>(p1.gety() - p2.gety());
	len = sqrt(x*x + y*y);

}
//组合类复制构造函数
line::line(const line &p11 ) 
{
    
    
	cout << "calling line copy construct" << endl;
	p1 = p11.p1;
	p2 = p11.p2;
	len = p11.len;
}
int main()
{
    
    
	point p1(1, 1), p2(4, 5);
	line line1(p1, p2);
	line line2(line1);
	cout << "the line 1 length is" << endl;
	cout << line1.getline() << endl;
	cout << "the line 2 length is" << endl;
	cout << line2.getline() << endl;
	return 0;
	
}




Los resultados de la operación de código son los siguientes:
resultado de la operación
Analicemos brevemente los resultados de la operación del programa. Primero mencionemos nuevamente cuándo usar el constructor de copia
. 1. Cuando se usa una clase existente para inicializar otra clase, el constructor de inicialización será llamado.
2. Cuando los parámetros formales de la función se combinan con virtual y real, se llama al constructor de copia de la función
3. Cuando se utiliza el objeto de la clase como valor de retorno, se llama al constructor de copia.

int main()
{
    
    
	point p1(1, 1), p2(4, 5);//初始化两个point 调用初始化point
	line line1(p1, p2);//进入到line构造函数时虚实结合,调用了point复制构造函数,接着在初始化列表中,用已有的类成员初始化另一个数据成员再次调用初始化构造函数。最后调用line 初始化构造函数
	line line2(line1);//进入到复制构造函数中先构造其中的两个point类,
	//调用了其中复制构造函数
	cout << "the line 1 length is" << endl;
	cout << line1.getline() << endl;
	cout << "the line 2 length is" << endl;
	cout << line2.getline() << endl;
	return 0;
	
}

El análisis anterior de la combinación de clases y el orden de los constructores, a continuación, describe la declaración de referencia directa de la clase. Sabemos que la clase se declara primero y luego se usa. Cuando nos encontramos con la situación en la que dos clases se llaman entre sí, Necesita la declaración de referencia directa de la clase. como sigue

class b;
class a{
    
    

void(b a1);
};
class b{
    
    };

Vale la pena señalar que, aunque se usa la declaración de referencia directa, los detalles de la clase no se pueden usar hasta que se proporcione una definición de clase completa, como

class b;
class a{
    
    

b a;
};
class b{
    
    };

Esto no es cierto, porque b no puede dar una definición completa de la clase. Al definir un tipo de datos, al menos debería saber cuántos bytes ocupa, ¿verdad? Debido a que no hay detalles completos, se informa un error.
Lo anterior es la combinación de clases y el uso de declaraciones de referencia hacia adelante.

Supongo que te gusta

Origin blog.csdn.net/qq_41803340/article/details/112596352
Recomendado
Clasificación