17. 虚析构函数再谈动态绑定多态到底是啥抽象类
Posted 为了财务自由!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了17. 虚析构函数再谈动态绑定多态到底是啥抽象类相关的知识,希望对你有一定的参考价值。
- 虚函数能产生函数地址!存储在虚函数表
- 对象必须存在,因为只有对象,才存在虚函数指针、表、虚函数地址
构造函数完成,对象才产生!
构造函数不能是virtual,构造函数调用虚函数,不会发生静态绑定!(构造函数中,调用的任何函数都是静态绑定的!)
派生类对象构造过程:先调用父类构造函数,再调用子类构造函数!
virtual+static是不行的,因为静态方法不依赖对象!(联想到第二点!)
//如果父类析构函数不是虚函数:
Base *pb = new Derive(10);
pb->show(); // 动态绑定 pb Base* *pb Derive
delete pb; // 派生类的析构函数没有被调用到!!!
编译器发现pb是个Base*类型,去Base类找,析构函数是个普通的函数,那么就是静态绑定了!直接调用Base!所以需要定义成虚析构函数!
那么虚析构函数,子类的析构函数在虚函数表中会把父类的虚析构函数覆盖掉,那么就先执行子类的析构函数了,由于继承,子类有父类的成员变量,那么子类会想办法析构父类,就调用了父类的析构函数!
什么时候把基类的析构函数必须实现成虚函数?
基类的指针(引用)指向堆上new出来的派生类对象的时候, delete pb(基类的指针)
,它调用析构函数的时候,必须发生动态绑定,否则会导致派生类的析构函数无法调用
虚函数动态绑定问题
是不是虚函数的调用一定就是动态绑定?不是的!
在类的构造函数当中,调用虚函数,也就是静态绑定(构造函数中调用其他虚函数,不会发生动态绑定!因为只有对象了,才有虚函数指针和表,构造函数执行完才有对象!)
如果不是通过指针或者引用变量来调用虚函数,那就是静态绑定
如何解释多态
// 动物的基类
class Animal
public:
Animal(string name) :_name(name)
virtual void bark()
protected:
string _name;
;
// 以下是动物实体类
class Cat : public Animal
public:
Cat(string name) :Animal(name)
void bark() cout << _name << " bark: miao miao!" << endl;
;
class Dog : public Animal
public:
Dog(string name) :Animal(name)
void bark() cout << _name << " bark: wang wang!" << endl;
;
class Pig : public Animal
public:
Pig(string name) :Animal(name)
void bark() cout << _name << " bark: heng heng!" << endl;
;
void bark(Animal *p)
p->bark(); // Animal::bark虚函数,动态绑定了
/*
下面的一组bark API接口无法做到我们软件涉及要求的“开-闭“原则
软件设计由六大原则 “开-闭“原则 对修改关闭,对扩展开放
p->cat Cat vftable &Cat::bark
p->dog Dog vftable &Dog::bark
p->pig Pig vftable &Pig::bark
*/
派生类继承了基类,对bark重写,那么虚函数表继承自基类的bark函数地址就被覆盖了。
继承的好处:
可以做代码的复用!
抽象类和普通类有什么区别?
一般把什么类涉及成抽象类?
/*
定义Animal的初衷,并不是让Animal抽象某个实体的类型
1.string _name; 让所有的动物实体类通过继承Animal直接复用该属性
2.给所有的派生类保留统一的覆盖/重写接口
拥有纯虚函数的类,叫做抽象类!(Animal)
Animal a; No!!!
抽象类不能再实例化对象了,但是可以定义指针和引用变量
*/
class Animal
public:
Animal(string name) :_name(name)
// 纯虚函数
virtual void bark() = 0;
protected:
string _name;
;
// 以下是动物实体类
class Cat : public Animal
public:
Cat(string name) :Animal(name)
void bark() cout << _name << " bark: miao miao!" << endl;
;
class Dog : public Animal
public:
Dog(string name) :Animal(name)
void bark() cout << _name << " bark: wang wang!" << endl;
;
class Pig : public Animal
public:
Pig(string name) :Animal(name)
void bark() cout << _name << " bark: heng heng!" << endl;
;
void bark(Animal *p)
p->bark(); // Animal::bark虚函数,动态绑定了
再举个例子:
//抽象类
class Car
Car(string name,double oil)
:_name(name),_oil(oil)
double getLeftMiles()
return oil * getMilesPerGalloc();//一加仑跑的公里数
//但是this->getMilesPerGalloc()动态绑定!
protected:
string _name;
double _oil;
virtual double getMilesPerCallon() = 0;//纯虚函数
;
class Bnze : public Car
public:
Bnze(string name,double oil) : Car(name,oil)
double getMilesPerCallon()
return 20.0;
;
class Audi: public Car
public:
Audi(string name,double oil) : Car(name,oil)
double getMilesPerCallon()
return 18.0;
;
class BMW: public Car
public:
Audi(string name,double oil) : Car(name,oil)
double getMilesPerCallon()
return 19.0;
;
//给外部提供一个统一的获取汽车剩余路程数的API
void showCarLeftMiles(Car& car)
//静态绑定 调用的是基类的函数!
cout << car.getName()<<"left miles:"<<car.getLeftMiles()<<"公里";
;
int main()
Bnze b1("奔驰",20.0);
Audi a("奥迪",20.0);
BMW b2("宝马",20.0);
showCarLeftMiles(b1);
showCarLeftMiles(a);
showCarLeftMiles(b2);
以上是关于17. 虚析构函数再谈动态绑定多态到底是啥抽象类的主要内容,如果未能解决你的问题,请参考以下文章