C++学习笔记十一———组合类及前向引用声明的使用

对于类,前面的文章分别简单讲述了什么是类,以及类的构造函数,类的复制构造函数的作用。前面文章的相关链接如下:
类的定义与初始化
复制构造函数与析构函数
那么下面将介绍组合类,什么是组合类?组合类有什么作用呢?通常我们在定义一个类的对象时,类成员的类型实际上通常为基本数据类型,如 int ,float,double…实际上类成员除了可以是基本的数据类型外,还可以是自定义数据类型,也就是说数据类型也可以是类的对象,那么如果定义一个组合类,那么类的构造顺序就很重要。利用前面提到过的构造函数对类进行初始化时,遵循以下构造顺序:
1.当类的成员类型为类的的对象时,首先初始化构造类成员数据。对类成员按照定义顺序进行构造,先定义先构造
2.构造完成员在构造自己
下面将举一个例子来说明问题,我们首先定义一个point类

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


};

每每使用初始化构造函数时,输出相应的调试语句,该类还包含了整数 x y ,
复制构造函数定义如下

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

可以看到point类的复制构造函数就是将对应成员 x y 一一复制给另一个成员。
下面定义一个line 类,line中包含了这个point 类,对应的line定义如下

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

};

我们看到使用了组合类的方式,使用point类作为line中的数据成员我们来看一下其中构造函数的内容

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

}

可以看到使用一个简单的初始化列表首先将point初始化,在根据两个point数据计算距离,并将值赋给 len。
看一下point的复制构造函数

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

以上就是line与point全部数据以及构造函数,下面我们在主函数中调用并观察以下构造的顺序。代码如下:

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




代码运行结果如下:
运行结果
我们来简单分析一下程序运行的结果,我们首先再次提及什么时候用复制构造函数
1.当用一个已有的类初始化另一个类会调用初始化构造函数。
2.当作为函数的形参虚实结合时调用函数复制构造函数
3.当类的对象作为返回值调用复制构造函数。

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

以上分析了类的组合以及构造函数的次序,下面介绍类的前向引用声明,我们知道类是先声明后使用,当我们遇到两个类相互调用的情况需要类的前向引用声明。如下

class b;
class a{
    
    

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

其中值得注意的是,虽然使用了前向引用声明,但是在提供一个完整的类定义之前,不能使用该类的细节,比如

class b;
class a{
    
    

b a;
};
class b{
    
    };

这样做是不成立的,因为b不能给出类的完整定义,在定义一个数据类型时,至少应该知道占用几个字节吧?因为没有完整的细节,所以报错。
以上就是类的组合以及前向引用声明的使用。

猜你喜欢

转载自blog.csdn.net/qq_41803340/article/details/112596352