基本概念
继承
在定义一个新的类B的时候,如果该类与某个已有的类A相似,指的是B拥有A的全部特点,那么就可以把A作为一个基类,而把B作为基类的派生类,也称子类。
派生
派生类是通过对基类进行修改或扩充而得到的。在派生类中可以扩充新的成员变量和成员函数。派生类已经定义后可以独立使用,不依赖基类。派生类拥有基类的全部成员函数和变量,不论是private、protected\public。在派生类的各个函数中,不能访问基类中的private成员。
派生类的体积
等于基类的体积再加上派生类对象自己的成员变量的体积。在派生类对象中,包含着基类对象,,而且基类对象的存储位置位于派生类新增的成员变量之前。
class Base
{//定义基类
int v1,v2;
};
class Driverd:public Base
{//定义派生类
int v3;
};
继承关系/复合关系
继承
"是"关系:对基类A,B是基类A的派生类,逻辑上要求:一个B对象也是一个A对象,例:一个中学生也是一个学生。
复合
类C中有成员变量k,k是类D的对象,则C和D是复合关系。一般逻辑上要求:D对象是C对象的固有属性或组成部分。例:每个圆都有一个特殊的点,这个点有位置x,y,即圆心,最好将其设置为圆的友元,使其可以访问必要的private成员变量。
派生类覆盖基类成员
覆盖
派生类可以定义一个和基类成员同名的成员,叫覆盖,在派生类中访问这类成员时,缺省的情况是访问派生类中定义的成员。要在派生类中访问由基类成员定义的同名成员时,要使用作用域符号 ::
class Base
{//基类
int j;
public:
int i;
void func();//基类的成员函数
};
class Derived:public Base
{//基类的派生类
public:
int i;//和基类成员同名的成员变量
void func();//和基类成员函数重名的覆盖函数
void access();
};
void derived::access()
{//派生类的成员函数
j=5;//error,派生类的成员函数不能访问基类的私有成员
i=6;//ok,缺省时派生类覆盖掉基类的成员
base::i=5;//ok,加上作用域限制,表示引用的是基类成员
func();//缺省时覆盖掉,调用派生类的成员函数
base::func();//ok,加上限制,引用的是基类的成员函数
}
一般来说,基类和派生类不定义同名的成员变量,但是定义了也不会出错。
类的保护成员
protected
是另一种存取权限说明符,可以访问的范围比private大一些,但是比public小一些
(1)基类的private成员,可以被下列函数访问
基类的成员函数
基类的友元函数
(2)基类的public成员可以被下列函数访问
基类的成员函数
基类的友元函数
派生类的成员函数
派生类的友元函数
其他的函数
(3)基类的protected成员,可以被下列函数访问
基类的成员函数
基类的友元函数
派生类的成员函数可以访问当前对象的基类保护成员
class Father
{//基类
private:
int nPrivate;//私有成员
public:
int nPublic;//公有成员
protected:
int nProtected;//保护成员
}
class Son:public Father
{//派生类
void AccessFather()
{//派生类的成员函数
nPublic=1;//ok,可以访问基类的公有成员
nPrivate=1;//error,不可以访问基类的私有成员
nProtetced=1;//ok,可以访问当前对象从基类继承的protected成员
Son f;//error,f不是当前对象,编译出错
f.nProtected=1;//f不是当前对象
}
};
Father f; Son s;
f.nPublic=1;//ok
s.nPublic=1;//ok
f.nProtected=1;//error,保护成员只能在基类的成员函数和友元函数或派生类的成员函数中被访问
s.nProtected=1;//error,保护成员只能在派生类的成员函数中访问
s.nPrivate=1;//error,私有成员只能被基类的成员函数或友元函数访问
派生类的构造函数
派生类的构造函数不能使用基类的私有成员变量进行初始化,可以通过将派生类包含的基类的私有成员变量在构造函数的初始化列表上初始化,其余自己的变量则可以放在构造函数的内部。
在创建派生类的对象时,需要调用基类的构造函数:初始化派生类对象中从基类继承的成员。在执行一个派生类的构造函数之前,总是先执行基类的构造函数。
调用基类构造函数的两种方式
- 显式:在派生类的构造函数中,为基类的构造函数提供参数,即写了初始化列表的derived::derived(arg_derived_list):base(arg_derived_list)
- 隐式:在派生类的构造函数中省略基类构造函数,派生类的构造函数自动调用基类的默认构造函数
派生类的析构函数被执行时,执行完派生类的析构函数后自动调用基类的析构函数。
包含成员对象的派生类的构造函数写法:总而言之就是要在初始化列表进行各种初始化
封闭派生类对象的构造函数执行顺序
在创建派生类的对象时
(1)先执行基类的构造函数,用以初始化派生类对象中从基类继承的成员
(2)再执行成员对象类的构造安徽念书,用以初始化派生类对象中的成员对象
(3)最后执行派生类自己的构造函数
派生类消亡时顺序相反
(1)先执行派生类自己的析构函数
(2)再一次执行各个成员类对象的析构函数
(3)最后执行基类的析构函数
(4)析构函数的调用顺序和构造函数的调用顺序相反
public继承的赋值兼容规则
规则
class base{};//基类
class derived:public base{};//公有派生类
base b;//基类对象
derived d;//派生类对象
1.派生类的对象可以赋值给基类对象即 b=d;即把d里面包含的b具有的成员赋值给b,反过来不可以,因为基类对象不是派生类的对象
2.派生类对象可以初始化基类引用 base &br=d;//ok
3.派生类对象的地址可以赋值给基类指针 base *pb=&d;//ok
4.如果派生对象不是public,而是private或protected,则上述三条不成立
直接基类和间接基类
(1)类A派生类B,类B派生类C,类C派生类D
类A是类B的直接基类
类B是类C的直接基类,类A是类C的间接基类
类C是类D的直接基类,类A\B都是类D的间接基类
(2)在声明派生类时,只需要列出它的直接基类
派生类沿着类的层次自动向上继承它的间接基类
派生类的成员包括:
派生类自己定义的成员
直接基类中的所有成员
所有间接基类中的全部成员
(3)析构和构造函数的执行
从最底层基类开始,依次执行知道执行完最外层的派生类构造函数
析构过程刚好相反