Derived derived(5);
// These are both legal!
Base &rBase = derived;
Base *pBase = &derived;
把派生类赋给基类,此时只保留基类特性
12.2虚函数与多态性
vitual
最优先调用最为派生的虚函数
12.2a重载和最后一个重载或者继承
override
final
12.3
虚拟解构器,虚拟赋值,重载虚拟化
删除某一类时,解构器需要设置为虚逆的,才能同时删除原类和派生类
不需要用虚拟函数时直接用存取符
12.4早起绑定和晚的绑定
早期绑定:编译器将用一条指令替换add()函数调用,该指令告诉CPU跳转到add()函数的地址
晚期绑定:延迟绑定,程序必须读取指针中保存的地址,然后跳转到该地址。
12.5虚拟表
虚拟函数都有虚拟指针,这是虚拟函数运行的原理
12.6纯虚函数、抽象基类和接口类
纯虚函数不能实例化
纯虚函数也有虚拟表
派生类必须完善虚函数
virtual const char* speak() = 0;
接口类:全部都是纯虚拟函数的类
可以派生出各种类
不要忘记为接口类包含一个虚拟析构函数,以便在删除指向接口的指针时调用正确的派生析构函数。
12.7 虚拟基类
class Printer: virtual public PoweredDevice
继承的是虚拟基类
虚拟基类优先被创建
最为派生的类负责虚拟基类的构造
12.8 对象切片
切片:把派生类赋值给基类得到基类
包含类的数组
#include
#include // for std::reference_wrapper
int main()
{
std::vector<std::reference_wrapper > v; // our vector is a vector of std::reference_wrapper wrapped Base (not Base&)
Base b(5); // b and d can’t be anonymous objects
Derived d(6);
v.push_back(b); // add a Base object to our vector
v.push_back(d); // add a Derived object to our vector
避免切片,对于对象尽量传地址
12.9dynamic_cast
Base *b = getObject(true);
Derived *d = dynamic_cast<Derived*>(b); // use dynamic cast to convert Base pointer into Derived pointer
一般用虚拟函数,少部分情况用dynamic_cast
12.10使用操作符<<打印继承类
混合使用一元和二元重载
#include
class Base
{
public:
Base() {}
friend std::ostream& operator<<(std::ostream &out, const Base &b)
{
return b.print(out);
}
virtual std::ostream& print(std::ostream& out) const
{
out << "Base";
return out;
}
};
class Derived : public Base
{
public:
Derived() {}
virtual std::ostream& print(std::ostream& out) const override
{
out << “Derived”;
return out;
}
};
int main()
{
Base b;
std::cout << b << ‘\n’;
Derived d;
std::cout << d << ‘\n’;
Base &bref = d;
std::cout << bref << ‘\n’;
return 0;
}