多态 polymorphism

—— 《21天学通C++》 

1、没有继承关系的类,分配完内存后,优先给虚表指针赋值,再列表初始化,再构造函数。有继承关系的类,分配完内存后,先基类构造,后续同上。

2、将函数声明(只能是类中的)为虚函数。放在函数声明最前。告诉编译器,调用复函的版本。将子类对象视为父类,并执行子类的函数实现。

3、使用new在堆中实例化的派生类对象,如果赋值给基类指针,并通过该指针调用delete,将不会调用派生类的析构函数。—— 内存泄露 (析构函数声明为虚函数)

4、假设基类有虚函数、子类覆盖了某些虚函数:编译器为实现了虚函数的基类和派生类,分别创建各自的虚函数表(Virtual Function Table, VFT)。实例化这些对象时,将创建一个隐藏的指针,指向虚函数表。VFT可以看做是一个包含函数指针的静态数组,每个指针都指向一个相应的虚函数(派生类:有指向父类的虚函数的;也有指向自己虚函数的指针,包括覆盖基类的函数)。VFT在编译阶段建立。VFT指针(虚表指针)放在对象的内存空间中最前面的位置。

有了虚函数表,通过指针、引用传递(指向派生类的基类)传递的指针依然实实在在的是指向派生类,因此可以调用派生类虚函数表内存的函数指针。

5、可以通过类型转换运算符dynamic_cast确定Base指针指向的是基类还是派生类(RTTI, RunTime Type Identification)

6、不能被实例化的基类(不能作为函数参数、不能创建对象、不能作为返回类型) —— 抽象基类(ABC)。需要声明至少一个纯虚函数。可以理解为抽象接口。

class AbstractBase {
public:
    virtual void DoSth() = 0; // 告诉编译器,子类必须实现这个方法
};

可以声明抽象类指针、引用

7、虚继承解决菱形问题。例:《21天学通C++》例子

Platypus具有多个Animal实例,占用多份内存。假设Animal里有一个int age成员变量,则鸭嘴兽存在三个不同的age。所以,Mammal、Bird、Reptile应该虚继承Animal

class Mammal : public virtual Animal {
    ...
};

class Platypus final : public Mammal, public Bird, public Reptile {
    ...
};

从Base使用virtual派生出Derived1、 Derived2类时,意味着从Derived1、 Derived2再派生出新的类Derived3时,只包含一个Base。

8、override —— 表明覆盖意图的限定符

class Fish {
public:
    virtual void Swim() {
        ...
    }
};

class Tuna : public Fish {
    void Swim() const {
        ...
    }
};

 此时子类函数并不会覆盖基类的虚函数。const 导致两个函数的特征不同。使用override来核实是否真的覆盖住了父类的虚函数,而不是重新写了一个不同的函数。

class Tuna : public Fish {
    void Swim() const override { // 此时编译出错,删除const可通过编译
        ...
    }
};

override让编译器做的检查:

a. 基类函数是否有虚函数?

b. 基类中虚函数特征与派生类override的函数是否相同?

9、被声明为final的虚函数,在子类中不能再进行覆盖

class Tuna : public Fish {
    void Swim() override final {
        ...
    }
};

class BluefinTuna final : public Tuna {
public:
    void Swim() { // 编译出错
        ...
    }
};

class Failed : public BluefinTuna { // 编译出错

};

10、可将赋值构造函数声明为虚函数吗 —— 不能。多态是运行时状态,而构造函数只能创建固定类型对象,不具备多态性。

class Fish {
public:
    virtual Fish *Clone() const  = 0;
};

class Tuna : public Fish {
public:
    Tuna *Clone() const { // TODO: 这里返回值写Tuna* 还是Fish *???
        return new Tuna(*this);
    }
};

 

11、基类总应该包含一个虚析构函数

12、虚函数表与虚基类表 虚表和虚基表到底有哪些区别? 

 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值