横向
组合
组合是一个类中包含另一个类对象,
组合关系的两个对象往往具有相同的生命周期,被组合的对象是在
组合对象创建的同时或者创建之后创建,在组合对象销毁之前销毁,
被组合对象不能脱离组
合对象独立存在。例如:人和心脏。
依赖
一个对象的某种行为依赖于另一个类对象,
只有在完成某个功能的时候才会用到,而且是必不可少的,
依赖之间是没有生命周期约束关系。例如:人和手机。
关联
完成
某个功能与被关联的对象有关,但是可有可无,被关联的对象与关联的对象无生命周期约束关系,被
关联对象的生命周期由谁创建就由谁来维护,被关联的对象还可以再被别的对象关联,所以关联是可以共享的。例如:人和朋友。
聚合
多个被聚合的对象聚集起来形成一个大的整体,聚合的目的是为了统一进行管理同类型的对象,聚合是一种弱所属关系,被聚合的对象还可以再被别的对象关联,所以被聚合对象是可以共享的,比关联关系更紧密。例如:一群学生一些老师组成一个班级。
纵向
继承
被继承的类叫做基类(父类),继承的类叫派生类(子类),在派生类类名后面加
: 继承方式 基类
class CFather{};
class CSon:public CFather{};
通过继承关系,子类可以使用父类的成员。如果子类和父类有同名的成员,默认使用子类的成员,如果想要使用父类的成员,需要在成员名前加上
类名::
用于显式的指定区分,
子类继承父类,相当于将父类的成员包含到自己的类里,所以定义
子类对象所占用的空间大小除了子类自身的成员还包括父类的成员
。
成员在内存空间分布为:先父类成员后子类成员,而每个类中的成员分布与在类中声明的顺序一致。
class CFather{
public:
int m_a;
};
class CSon:public CFather{
public:
int m_a;
};
int main(){
Cson son;
son.m_a; //子类成员
son.CSon::m_a; //子类成员
son.CFather::m_a; //父类成员
return 0;
}
继承构造析构顺序:
定义子类对象时执行顺序:父构造->子构造->孙构造...| ...孙析构->子析构->父析构。
构造顺序:在子类创建对象的时候,调用子类的构造函数(注意这里并不是直接先执行父类的构
造函数),但要先执行构造的初始化列表,在初始化列表中会默认调用父类的无参构造初始化父类成员,
如父类只有带参数的构造,在子类的初始化参数列表中必须显式的指定父类构造进行初始化
。这有点像之前说的组合关系形式。
析构顺序:子类对象的生命周期结束后,因为是子类所以自动调用子类析构,当析构执行完了,才会回收对象分配的空间,当然这个空间包含创建的父类的成员,那么回收父类成员前,自动调用父类的析构。如果是new
出来的子类对象,同理。
继承方式:
三种继承方式
public
、
protected
、
private
继承方式与访问修饰符共同决定了父类成员在子类中所表现的属性

隐藏:
对于父类和子类,如果有同名的函数但是参数列表不同,则不能够自动区分匹配,因为他们之间 的关系并不是函数重载的关系,作用域不同,必须使用 类名:: 去区分到底该调用哪个函数。这种关系一般称之为 隐藏。子类对象调用时默认走自己的那个。
class CFather {
public:
void fun();
};
class CSon :public CFather {
public:
void fun(int a); //隐藏关系,自动将父类的成员屏蔽了
};
父类的指针指向子类的对象:
继承关系下,允许父类的指针指向子类的对象,但是反过来却不行。 好处是:父类的指针可以统一多个类的类型,提高代码的复用性、扩展性。父类的指针只能使用父类的成员,不能使用子类的成员。
CFather * p = new CSon;
CSheep,CDog,CPig都继承Cpet可以通过父类指针统一管理三种子类对象,减少了代码量。
class CPet
{
public:
int m_weight;
void walk()
{
cout << "散步" << endl;
}
CPet()
{
m_weight = 20;
}
};
class CSheep:public CPet
{
public:
void like()
{
cout << "喜欢吃草" << endl;
}
};
class CPig :public CPet
{
public:
void like()
{
cout << "喜欢胡萝卜" << endl;
}
};
class CDog :public CPet
{
public:
void like()
{
cout << "喜欢骨头" << endl;
}
};
//父类的指针可以统一多种子类类型,减少代码的冗余,提高程序复用性、扩展性
void fun(CPet *pCPet)
{
cout <<"体重: " << pCPet->m_weight << endl;
//pCPet->like(); //父类的指针只能使用父类的成员,不能使用子类的成员
pCPet->walk();
}
int main()
{
fun(new CSheep);
fun(new CPig);
fun(new CDog);
return 0;
}
继承优点:
可以将类中的一些功能相近、相似的共同的方法,抽离出来放到单独的一个类中,并让其继承这个类,那么抽离出来的类就是父类,将来其他类在增加公共的方法时,我只需要在父类添加一份即可。提高了代码的复用性、扩展性。