一、关于C++动态绑定的问题,来来回回看了很多遍,现在终于有点稍微的理解。谈下自己的想法。
参考文章:(写得很好) http://blog.csdn.net/haoel/article/details/1948051/
为什么析构函数要声明为虚函数 http://www.cnblogs.com/lixiaohui-ambition/archive/2012/07/13/2589716.html
二、自己的一些理解
1、CPP Plus中说,C++中实现动态绑定需要有两个基本条件
a.指向基类的指针和引用
b.子类对基类的虚函数进行重定义。(函数定义原型完全一样,除一个特例,下面介绍)
#ifndef _VIRTUAL_H_ #define _VIRTUAL_H_ using namespace std; class A{ public: virtual void p() { cout<<"A"<<endl; } virtual ~A() { cout<<"deconstruction A"<<endl; } }; class B: public A { public: void p() { cout<<"B"<<endl; } ~B() { cout<<"deconstruction B"<<endl; } }; class C: public B { public: void p() { cout<<"C"<<endl; } ~C() { cout<<"deconstruction C"<<endl; } }; #endif
如上代码,A为基类,B public 继承 A。 C public 继承
B。
补充一些继承的概念:所有基类的成员变量和成员数据在派生类中都存在。继承的权限只是决定派生类的对象是否有访问基类的权利。
#include "stdafx.h" #include <iostream> #include "virtual.h" int _tmain(int argc, _TCHAR* argv[]) { A *a = new A; A *b = new B; A *c = new C; a->p(); b->p(); c->p(); delete a; delete b; delete c; system("pause"); return 0; }
动态绑定的实现:如上代码,生成
A、B、C三类对象,都使用基类的指针来指向该内存空间。执行p()函数时(p函数实现了重定义),将根据动态绑定选择执行哪个类的函数(满足C++动态绑定的两个要求)
动态绑定的实质是:对虚表的查询(详解链接一中说明)。虚表中保存每个函数的实际地址。
其实对于 class C 的 p()函数是virtual函数,则无论使用 A *c = new C, 或 B *c = new C, 还是 C *c = new C, 使用 c->p(),调用的都是 class C 中重定义过的 p()
但是如果 class C 的 p() 函数不是virtual函数:
#则使用 A *c = new C, c->p() 调用的是class A 中的 p(),
#使用 B *c = new C, c->p() 调用的是class B 中的 p(),
#使用 C *c = new C, c->p() 调用的是class C 中的 p().
2、为什么虚构函数要使用虚函数
调用派生类的虚构函数执行后,默认调用基类的析构函数。虚构函数声明为虚函数,主要是:当使用delete释放指向基类的指针时,可以正确地选择要调用的虚构函数。实现虚构函数的动态绑定。
注意:虽然每个派生类的虚构函数名称不同,但是实质上是同一类型。基类的析构函数声明为虚函数,则子类的虚函数在虚表里覆盖基类的析构函数。
3、虚函数重定义
虚函数的重定义必须保证函数原型的一致,否则将被认为是新的函数,而不是对基类虚函数的重定义。有两个特例
a.如 3 中所说,析构函数虽然名称不同,但属于重定义。
b.若基类虚函数的返回值是基类的引用或指针,则子类重定义虚函数的返回值可以是子类(或父类)的引用和指针
3、虚函数的意义
还在思考中。(TODO)