当我们使用基类的引用或指针调用基类中定义的一个函数时,运行时才会知道他到底执行的哪个版本的函数。
而非虚函数或者通过对象调用时,编译的时候就决定调用哪个版本的函数
#include <iostream> using namespace std; class PP1 { public: void Print1() { cout << "PP1" << endl; } virtual void Print2() { cout << "PP2" << endl; } }; class PP : public PP1 { public: void Print1() { cout << "PPP1" << endl; } void Print2() override { cout << "PPP2" << endl; } }; int main() { auto* p = new PP(); p->Print1(); p->Print2(); auto* p2 = (PP1*)p; p2->Print1(); p2->Print2(); }
输出结果:
PPP1
PPP2
PP1
PPP2
调用虚函数前,申明类
auto* p = new PP(); p->Print1(); p->PP1::Print2();
虚函数后面加=0就是纯虚函数,含有纯虚函数的类是抽象基类,是不能直接创建对象的。
而且派生类必须给纯虚函数定义,否则他们仍是抽象基类。
注:纯虚函数不能在声明里定义,但可以在外部定义
介于public和private中间的字段:外部不可直接访问,但是派生类内可以访问
在对应的级别,使用using声明语句
public: using base::pri_data;
struct默认继承public类型,class默认继承pri类型。
最好声明的时候,显示的声明出来。
c++11功能。通过【using 基类:基类】的写法可以继承基类的构造函数
注意:如果基类有默认实参,派生类不会继承。派生类回生成多个构造函数,比如基类是一个形参+一个实参,派生类会生成一个形参的构造函数+两个形参的构造函数
注意2:默认、拷贝和移动构造函数不会被继承
多重继承主要需要注意的就是成员的二义性。如果两个基类有同一个名称的成员,需要在前面声明类名。
构造顺序:先父类,后子类
析构顺序:先子类,后父类
解决问题:同一个类多次继承一个类的问题。B、C分别继承A,D继承B、C,此时D继承了两次A。使用虚继承可以确保在D中只有一个A的基类部分。
虚基类:虚继承某个类的类
虚派生只影响从指定了虚基类的派生类中进一步派生出的类,它不会影响派生类本身。
class Raccoon : public virtual ZooAnimal {}; class Bear : virtual public ZooAnimal {};
首先使用提供给最底层派生类构造函数的初始值初始化该对象的虚基类子部分,接下来按照直接基类在派生列表中出现的次序依次对其进行初始化。
比如上面的ABCD。构造顺序是:A->B->C->D
如果未声明虚基类,构造顺序是:A->B->A->C->D
虚函数总是先于非虚基类构造,与他们在继承体系中的次序和位置无关
和构造顺序相反
如果不希望该类被其他类给继承,就在类名后申明final
class Last final { }
如果不希望该方法被派生类给覆盖,就在方法后申明final
struct A { void Print() const final; }
如果写的函数没有覆盖到基类的虚函数,会报错