保持原有特性:继承
👇
新增自己的特性:派生
一些名词
基类/父类: 被继承的已有类(共性)
派生出的新类: 派生类 (特性)
派生类
可以继承: 除构造/析构/静态成员以外的所有
派生类的构造
吸收: 基类除构造/析构/静态成员以外的所有成员
改造:
- 继承的成员用定义时的继承方式控制(即在派生类中如何访问)
- 隐藏基类成员:派生类中声明一个同名(为成员函数时还要同参数)的成员👉完全替代了继承而来的
新添:
- 必要:构造+析构
各类型继承特点
公有继承:
-
基类public/protected👉派生类public/protected
-
在派生类中的函数
-
访问基类public/protected√ 访问子类任一(?)
-
访问基类private×
-
派生类创建的对象
-
只能访问基类public
-
访问派生类任意
私有继承:
- 基类public/protected👉派生类private
- 在派生类中的函数
-
访问基类public/protected√ 访问子类任一(?)
-
访问基类private×
- 派生类创建的对象
-
不能访问基类任何成员
-
可以访问派生类任一(???)
保护继承:
- 基类public/protected👉派生类protected
- 在派生类中的函数
-
访问基类public/protected√ 访问子类任一(?)
-
访问基类private×
- 派生类创建的对象
-
不能访问基类任何成员
-
可以访问派生类任一(???)
需要基类对象时-类型转换规则
前提:
- 使用的是从基类继承的成员(函数/数据)
-
即使子类也有此函数声明,但使用的是基类
- 需要基类对象(作参数之类的)
(Base1类中有display函数)#前提1
void fun(Base1* ptr) {//一个函数,形参是指向->基类base1的对象的 指针*ptr
ptr->display();//调用类中成员函数:对象指针->成员名
(base2继承base1)
fun(&base1);//基类对象调用fun函数
fun(&base2);//子类对象调用fun函数,此处需要基类对象,使用共有派生类的对象,可以隐含转换为基类对象
fun(&derived);//根据类型转化,可以将共有派生类对象的地址赋给基类类型的指针
派生类的构造函数
(各自的构造函数)
B(int i);//形参为int的构造函数
C(int i, int j);
(C继承B)
C::C(int i,int j):B(i),c(j)//子类C的构造函数
{
cout << "C's constructor called." << endl;
}
- 派生类的构造函数需要给基类的构造函数传递参数
- 基类中声明缺省构造函数/未声明构造函数时,派生类构造函数可以不管基类参数
多继承时:
SON::SON(int a,int b,int c):FATHER(a),MOTHER(b),SON(s){
//其他实现
}
多继承+有内嵌对象时:
SON::SON(int a,int b,int c):FATHER(a),MOTHER(b),SON(s),本类对象成员和基本类型成员初始化{
//其他实现
}
构造函数的执行顺序:
- 调用基类构造函数:按声明时顺序
- 对成员(本类成员/基本类型成员/对象成员)初始化:按类体中声明的顺序
- 执行派生类构造函数
基类与子类同名成员的使用(适用于单+多继承)
隐藏: 子类与父类有同名成员,子类对象调用时用的是子类成员
去隐藏: 父类::修饰
d.var = 1;//子类对象访问同名成员,默认本类成员
d.fun();
d.base1::var = 2;//子类对象要访问父类成员,父类::修饰
d.base1::fun();
基类与基类同名(多继承)-二义性
- 类名限定
- 在子类中声明同名函数隐藏两个基类,在子类中根据需要调用A::f()/B::f()
爷+两个爸+一个儿子:
虚基类解决双层基类问题
有爷,两个爸,一个儿子时,将爷虚基,避免二义性+简化子类到爷类的访问
class base1 :virtual public base0 {//1继承0;0是虚基类
大大简化了子类数据成员(可以不通过两个爸,直接到爷)