C++继承
继承
通过继承机制可以实现对代码的拓展以及重用,而不用通过复制粘贴的方式来实现重用
继承语法:Class B : public A{ ... }
; public是公用继承用的最多,B是子类(派生类),A是父类(基类)
子类可以访问从父类被public修饰的成员变量和函数,以及一些新增加的函数和变量,子类不能直接访问父类的private修饰的成员。
虚函数:在类中声明成员函数为虚函数,是为了便于子类对父类函数的override(重写)
虚函数工作原理:通常编译器处理虚函数:给每个对象添加一个隐藏成员(vptr),隐藏成员(vptr)是一个指向函数地址数组的指针,这种数组成为虚函数表(virtual function table, vtbl)。虚函数表中存放的是为类对象进行声明的虚函数的地址。用《C++ Primer Plus》书中的例子来说明虚函数工作原理:
Physicist adam("Adam Crusher", "nuclear structre");
Scientist * psc = &adam; //这里发生的是upcasting向上造型
psc->show_all();
psc->show_all()
执行过程:
- 通过
psc->vptr
找到Physicist对象vptr中的值2096 - 通过地址2096找到对应的虚函数表
- 在表中寻找
Physicist::show_all
地址6820 - 跳转到地址6820去执行相应的函数
多态(Polymorphic):方法的行为取决于调用该方法的对象,同一个方法的行为随上下文而异。
实现多态的两种机制:
- 父类函数添加virtual关键字
- 子类中重写父类被virtual修饰的函数
纯虚函数(pure virtual functions):父类只有虚函数的声明,父类不能实例化,此时父类像是一个接口(interface),强制子类实现虚函数
举个例子:
声明一个抽象类Creature,让Animal类继承并实现其中的纯虚函数,Dog类再继承Animal类并重写play(),将Dog类对象、Animal类对象作为参数传递给void showPlay(Creature& c)
,会根据参数的类型选择其对应的函数。继承关系图:
#include <iostream>
using namespace std;
/******抽象类*******/
class Creature
{
public:
virtual void sleep() = 0; //pure virtual function
virtual void eat() = 0; //pure virtual function
virtual void play() = 0;
};
/****************/
class Animal : public Creature
{
public:
void sleep() { cout << "Animal is sleeping...\n"; }
void eat() { cout << "Animal is eatting...\n"; }
virtual void play() { cout << "Animal is playing...\n"; }
};
class Dog : public Animal
{
private:
double weight;
public:
virtual void play() { cout << "Dog is playing...\n"; } //重写父类的play(),C++11增加override关键字,增加可读性
//也可以这么写:
//virtual void play() override { cout << "Dog is playing...\n"; }
};
void showPlay(Creature& c)
{
c.play();
}
int main()
{
//Creature c; //报错,抽象类不能实例化
Animal a;
Dog d;
showPlay(a); //call Animal::play()
showPlay(d); //call Dog::play()
return 0;
}