C++系列:继承和派生(四)
继承和派生
继承和派生的概念
- 继承:在定义以恶搞新的类B时,如果该类与某个已有的类A相似(指的是B拥有A的全部特点),那么就可以把A作为一个基类,而把B作为基类的一个派生类(也称子类)。
- 派生类是通过对基类进行修改和扩充得到的。在派生类中,可以扩充新的成员变量和成员函数。
- 派生类一经定义后,可以独立适用,不依赖于基类。
- 派生类拥有基类的全部成员函数和成员变量,不论是private、protected、public。
- 在派生类的各个成员函数中,不能访问基类中的private成员。
需要继承的例子
派生类的写法
|
派生类对象的内存空间
- 派生类对象的体积,等于基类对象的体积,再加上派生类对象自己的成员变量的体积。在派生类对象中,包含着基类对象,而且基类对象的存储位置位于类派生类对象新增的成员变量之前。
class CBase |
- 派生类对象包含基类对象,派生类对象新增的内容位于基类对象之后
//实例 |
继承关系和复合关系
-
继承 “是”关系
- 满足逻辑要求“ 一个B对象也是一个C对象”
- 基类A,B是基类A的派生类
-
复合 “有”关系
- 类C中“有”成员变量k,k是类D的对象,则C和D是复合关系
- 一般逻辑上要求:“D对象是C对象的固有属性或组成部分”
-
继承关系使用
- 人 对男人和女人 的关系,把人作为基类,男人和女人作为人的派生类
-
复合关系使用
-
需要“点”类,也需要“圆”类时,两者的关系就是复合关系,即每一个圆包含一个点
//正确做法
class CPoint
{
double x,y;
friend class CCircle;
//便于Ccirle类操作其圆心
};
class CCircle
{
double r;
CPoint center;
}; -
小区业主与狗的关系
//这样的定义是错的,循环定义了
class CDog;
class CMaster
{
CDog dogs[10];
};
class CDog
{
CMaster m;
};
//改进
class CDog;
class CMaster
{
CDog * dogs[10]; //CDog类的指针数组
};
class CDog{
CMaster m;
};
//依然不行 在调用修改狗的主人的信息时,需要维持不同狗之间的一致性,比较繁琐
//再次改进
class CMaster; //先声明
class CDog{
CMaster *pm;
};
class CMaster{
//这样使得狗对象只能通过人来调用,失去了自由
CDog dogs[10];
};
//正确做法
class CMsater;
class CDog{
CMaster *pm;
};
class CMaster{
CDog *dogs[10]; //这种关系也被称为"知道"
};
-
派生类覆盖基类成员
-
派生类可以定义一个和基类成员同名的成员,这叫做覆盖。== 在派生类中访问这类成员时,缺省的情况是访问派生类中定义的成员。要在派生类中访问由类定义的同名成员时,要使用作用域符号 ::
class base//基类
{
int j;
public:
int i;
void func();
};
class derived:public base//派生类
{
public:
int i;
void access();
void func();
};
void derived::access() //派生类的成员函数
{
j=5; //这里是在派生类里找,错误error
i=5; //派生类i
base::i =5; //基类i
func();//派生类fun
base::func();//基类fun
}
//注意
一般来说,基类和派生类不定义同名的成员变量
//占用空间
| base::j |
| base::i |
| i |
类的保护成员
private: //基类的成员函数、友元函数可以访问 |
派生类的构造函数
|
-
调用基类构造函数的两种方式
-
显示方式:在派生类的构造函数中,为基类的构造函数提供参数
derived::derived(arg_derived-list):base(arg_base-list)
-
隐式方式:在派生类的构造函数中,省略基类构造函数时,派生类的构造函数则自动调用基类的默认构造函数。
-
包含成员对象的派生类的构造函数写法
class Bug{ |
生成时:
- 先执行基类的构造函数,用以初始化派生类对象中的从基类继承的成员;
- 在执行成员对象类的构造函数,用以初始化派生类对象中成员对对象。
- 最后指向派生类自己的析构函数
消亡时:
- 先执行派生类自己的析构函数
- 再一次执行各成员对象类的析构函数
- 最后执行基类的析构函数
析构函数的调用顺序与构造函数的调用顺序相反
public 继承的赋值兼容规则
class base{}; |
-
派生类对象可以赋值给基类对象
b = d;
-
派生类对象可以初始化基类引用
base & br = d;
-
派生类对象的地址可以赋值给基类指针
base * pb = & d;
直接基类与间接基类
A-派生-B-派生-C
A是B的直接基类,A是C的间接基类
- 声明派生类时,只需要列出它的直接基类
- 派生类沿着类的层次自动向上继承它的间接基类
- 派生类的成员包括
- 派生类自己定义的成员
- 直接基类中的所有成员
- 所有间接基类的全部成员
|
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Q's blog!
评论