4.4类的组合
类的组合是要干什么?在面向对象程序设计中,可以对复杂对象进行分解、抽象,把一个复杂对象分解为简单对象的组合,由比较容易理解和实现的部件装配而成。
4.4.1组合
class Circle{//定义类circle及其数据和方法
public: //外部接口
Circle(float r);//构造函数
float circumference();//计算圆周长
float area();//计算圆面积
private:
float radius;//半径
};
上面的例子说明类中包含float类型的数据,类的成员数据可以是什么?基本类型、自定义类型、类。
类的组合定义的理解:类的成员数据可以是类,这就是用已有类构建新的类,这就是类的组合。类的组合描述的是一个类内嵌其他类的对象作为成员的情况,他们的关系是一种包含与被包含的关系。
组合类构造函数定义的一般形式:
类名::类名(形参表):内嵌对象1(形参表),内嵌对象2(形参表){
函数体
}//橙色部分叫初始化列表,作用是对内嵌对象进行初始化
Ps:这种定义形式不光内嵌对象可以用,基本类型也可以。
当创建类的对象时,如果这个类具有内嵌对象成员,那么各个内嵌对象将被自动创建。因为部件对象是复杂对象的一部分。在创建对象时,既要对本类的基本类型数据成员进行初始化,又要对内嵌对象成员进行初始化。那么这些对象的构造函数被调用的顺序是什么呢?
(1)调用内嵌函数的构造函数,调用顺序按照内嵌对象在组合类的定义中出现的次序,不是在构造函数的初始化列表中的顺序;
Ps:如果本类中的初始化列表中有些内嵌函数没有出现,那该内嵌函数的默认构造函数将被执行,默认构造函数的函数体为空,但是执行默认构造函数时,如果声明组合类的对象时没有指定对象的初始值,则默认形式(无形参)的构造函数被调用,这时内嵌函数的默认形式构造函数也会被调用,隐含 的默认构造函数并非什么也不做。
两种数据成员的初始化必须在构造函数的初始化列表中进行:1,那些没有默认构造函数的内嵌对象(因为这类对象初始化时必须提供参数);2,引用类型的数据成员(因为引用型变量必须在初始化时绑定引用的对象)。如果一个类中出现上面两种数据成员,那么编译器不能为这个类提供隐含的默认构造函数,这时必须编写显式的构造函数,并且为每个构造函数的初始化列表中至少为这两类数据成员进行初始化。
(2)执行本类构造函数的函数体;
析构函数的调用执行顺序与构造函数刚好相反,析构函数的函数体被执行完毕后,内嵌对象的析构函数将被一一执行,这些内嵌对象的析构函数调用顺序与它们在组合类中的定义中出现的次序刚好相反。Ps:由于要调用内嵌函数的析构函数,所以有时隐含的析构函数并非什么也不做。
那么有组合类时,复制构造函数应该如何编写?
如果无复制构造函数,那么编译系统会自动生成一个隐含的复制构造函数,这个隐含的函数会自动调用内嵌函数的复制构造函数,为各个内嵌对象初始化。
如果要自己写一个复制构造函数,则要为内嵌成员对象的复制构造函数传递参数。
例如:C类中包含B类的对象b作为成员,C类的复制构造函数形式:
C::C(C &c1):b(c1.b){…}
对上面形式的理解:作用域是大类,函数名与大类名同名,无返回值,形参表是大类名 引用传递,初始化列表是内嵌对象,内嵌对象的形参表是用来初始化的,也就是复制构造的对象c1的b
例4-4类的组合,线段(Line)类
#include<iostream>
#include<cmath>
using namespace std;
class Point{ //Point类定义
public:
Point(int xx=0,int yy=0){
x=xx;
y=yy;
}//有参构造函数
Point(Point &p);
int getX(){return x;}
int getY(){return y;}
private:
int x,y;
};
Point::Point(Point &p)//复制构造函数的实现
{
x=p.x;
y=p.y;
cout<<"复制构造函数被调用"<<endl;
}
//类的组合
class Line{
public:
Line(Point xp1,Point xp2);
Line(Line &l);
double getlen(){return len;}
private:
Point p1,p2;
double len;
};
//组合类的构造函数
Line::Line(Point xp1,Point xp2):p1(xp1),p2(xp2)
{
cout<<"组合类的构造函数被调用"<<endl;
double x=static_cast<double>(p1.getX()-p2.getY());//static_cast<double>是强制类型转换
double y=static_cast<double>(p1.getX()-p2.getY());
len=sqrt(x*x+y*y);
}
//组合类的复制构造函数
Line::Line(Line &l):p1(l.p1),p2(l.p2)
{
cout<<"组合类的复制构造函数被调用"<<endl;
len=l.len;
}
//主函数
int main()
{
Point myp1(1,1),myp2(2,2);//创建point类对象
Line line(myp1,myp2);//建立line类对象
Line line2(line);//用复制构造函数建立一个新对象
cout<<"线段长度:"<<line.getlen()<<endl;
cout<<"线段2长度:"<<line2.getlen()<<endl;
return 0;
}