公有继承
class 子类名: public 父类名{
};
继承方式:
父类 | 子类 |
public | public |
protected | protected |
private | 不能读取父类的private |
私有继承
类继承的缺省继承方式是private继承。
class 子类名: private 父类名{
};
父类 | 子类 |
public | private |
protected | private |
private | 不能读取父类的private |
保护继承
class 子类名: protected 父类名{
};
父类 | 子类 |
public | protected |
protected | protected |
private | 不能读取父类的private |
基类的protected成员不能被派生类的对象访问。
同名覆盖
- 子类修改基类的成员,是在子类中声明了一个与父p;类成员同名的新成员。
- 在子类作用域内或者在类外通过子类的对象直接使用这个成员名,只能访问到子类中生命的同名新成员,这个新成员覆盖了从基类继承的同名成员,这种情况称为同名覆盖。
- 需要注意的是,同名覆盖的函数的函数名、参数需要完全一样,否则函数会被重载而不是被同名覆盖。
子类的构造和析构函数
- 基类的构造函数和析构函数不能直接被派生类所继承。
- 派生类一般需要自己定义构造和析构函数。
- 派生类的构造及析构函数通常会收到基类的影响。
若基类只有无参数构造函数:
- 在基类具有无参构造函数,派生类又没有定义构造函数的时候,系统会自动调用基类的无参构造函数来构造派生类对象中的基类部分。
- 基类的构造函数一般为public的访问控制方式。若基类提供了一些构造函数,并且只希望由派生类使用这些函数,那么就需要在基类中将这样的特殊构造函数定义为protected。
派生类没有自己的析构函数,需要自己定义析构函数,以便在派生类对象消亡之前进行必要的清理工作。
- 派生类的析构函数只负责清理它新定义的成员,一般来说,只清理位于堆区的成员。
- 如果没有特殊指针数据成员需要清理,可以使用由系统默认提供的析构函数。
- 当派生类对象消亡时,系统调用析构函数的顺序与建立派生类对象时调用构造函数的顺序正好相反,即先调用派生类的析构函数,再调用基类的析构函数。(即构造时:基类->派生类,析构时:派生类->基类)。
多继承
多继承即一个子类可以有多个父类,它继承了多个父类的特性。
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};
C++ 提出了虚继承,使得在派生类中只保留一份间接基类的成员。
在继承方式前面加上 virtual关键字就是虚继承,请看下面的例子:
//间接基类A
class A{
protected:
int m_a;
};
//直接基类B
class B: virtual public A{ //虚继承
protected:
int m_b;
};
//直接基类C
class C: virtual public A{ //虚继承
protected:
int m_c;
};
//派生类D
class D: public B, public C{
public:
void seta(int a){ m_a = a; } //正确
void setb(int b){ m_b = b; } //正确
void setc(int c){ m_c = c; } //正确
void setd(int d){ m_d = d; } //正确
private:
int m_d;
};
int main(){
D d;
return 0;
}
这段代码使用虚继承重新实现了上图所示的菱形继承,这样在派生类 D 中就只保留了一份成员变量 m_a,直接访问就不会再有歧义了。
虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class),本例中的 A 就是一个虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。
转换与继承
每个派生类对象包含一个基类部分,这意味着可以使用基类对象一样在派生类对象上执行积累的操作。这就涉及到派生类和基类的转换。该转换包括以下三种情况:
- 派生类对象转换成基类对象(用派生类对象给基类对象赋值)
- 基类对象指针指向派生类对象。
- 用派生类对象初始化基类对象的引用。
给你加油