C++ study notes eleven-the use of combination classes and forward reference declarations

For classes, the previous articles briefly described what a class is, its constructor, and the role of its copy constructor. The related links of the previous article are as follows:
class definition and initialization
copy constructor and destructor
Then the following will introduce composite classes, what is a composite class? What is the role of the combination class? Usually when we define an object of a class, the types of class members are actually basic data types, such as int, float, double... In fact, class members can be not only basic data types, but also custom data types. That is to say, the data type can also be the object of the class , so if a composite class is defined, the order in which the class is constructed is very important. When using the aforementioned constructor to initialize a class, follow the construction sequence as follows:
1. When the member type of the class is an object of the class, first initialize the structure of the class member data. The class members are constructed in the order of definition, first define first to construct
2. The constructor is constructing himself.
Here is an example to illustrate the problem, we first define a point class

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);//复制构造函数


};

Whenever the initialization constructor is used, the corresponding debugging statement is output. This class also contains the integer xy. The
copy constructor is defined as follows

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

You can see that the copy constructor of the point class copies the corresponding members xy to another member one by one.
The following defines a line class, the line contains the point class, and the corresponding line is defined as follows

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

};

We have seen the use of composite classes, using the point class as the data member in the line, let’s take a look at the content of the 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);

}

It can be seen that a simple initialization list is used to initialize the point first, calculate the distance based on the two point data, and assign the value to len.
Take a look at the copy constructor of point

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

The above is all the data and constructors of line and point. Below we call and observe the sequence of the following constructions in the main function. code show as below:

# 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;
	
}




The code running results are as follows:
operation result
Let's briefly analyze the results of the program running, we first mention again when to use the copy constructor
1. When an existing class is used to initialize another class, the initialization constructor will be called.
2. When the function's formal parameters are combined with virtual and real, the function copy constructor is called
3. When the object of the class is used as the return value, the copy constructor is called.

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;
	
}

The above analyzes the combination of classes and the order of constructors. The forward reference declaration of the class is introduced below. We know that the class is declared before use. When we encounter the situation where two classes call each other, we need the forward reference declaration of the class. as follows

class b;
class a{
    
    

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

It is worth noting that although the forward reference declaration is used, the details of the class cannot be used until a complete class definition is provided, such as

class b;
class a{
    
    

b a;
};
class b{
    
    };

This is not true, because b cannot give a complete definition of the class. When defining a data type, you should at least know how many bytes it occupies, right? Because there is no complete details, an error is reported.
The above is the combination of classes and the use of forward reference declarations.

Guess you like

Origin blog.csdn.net/qq_41803340/article/details/112596352