您的位置:首页 > 编程语言 > C语言/C++

C++专题总结之理解虚拟函数、多继承、虚基类和RTTI

2017-01-02 16:55 190 查看
主题概要
C++虚拟函数、多继承、虚基类、RTTI
编辑时间
新建20170102
序号参考资料
1More effective C++
2http://blog.csdn.net/haoel/article/details/1948051

虚拟函数

记得以前面试的时候,面试官问了个问题,“多态的本质是什么”?

当时没答上来,现在想想如果能说出虚拟函数表来应该就可以了。

所谓虚函数的“虚”是指“直到运行时才能知道要调用的是哪一个函数”。那通过什么方法确定?答案是虚函数表和虚函数表指针。virtual table和virtual table pointers通常被分别地称为vtbl和vptr。

一个vtbl通常是一个函数指针数组。在程序中的每个类只要声明了虚函数或继承了虚函数,它就有自己的vtbl,并且类中vtbl的项目是指向虚函数实现体的指针。

例如这个类:

class C1
{
public:
C1();
virtual ~C1();
virtual void f1();
virtual int f2(char c) const;
virtual void f3(const string& s);
void f4() const;
};


虚函数表数组,看起来像这样:



注意非虚函数f4不在表中,而且C1的构造函数也不在。

如果有一个C2类继承自C1,重新定义了它继承的一些虚函数,并加入了它自己的一些虚函数:

class C2 : public C1
{
public:
C2();               // 非虚函数
virtual ~C2();     // 重定义函数
virtual void f1();  // 重定义函数
virtual void f5(char *str); // 新的虚函数
};


它的virtual table项目指向与对象相适合的函数。这些项目包括指向没有被C2重定义的C1虚函数的指针,而f1被替换为子类重定义的指针:



如果有一函数调用:

ptr->f1();

根据这个虚函数表就能确定要执行哪个函数了。

实际上根据虚函数表只是完成了一半的工作,假设新建一个对象时,怎么样确定这个对象是使用哪一个虚函数表?只有用某种方法指出每个对象对应的vtbl(虚函数表)时,它们才能使用。这是virtual table pointer的工作,它来建立这种联系。

每个声明了虚函数的对象都带有它,它是一个看不见的数据成员,指向对应类的virtual table。

我们可以认为包含有虚函数的对象的布局是这样的:



假如我们有一个程序,包含几个C1和C2对象。对象、vptr和刚才我们讲述的vtbl之间的关系,在程序里我们可以这样去想象:



考虑这段这段程序代码:

void makeACall(C1 *pC1)
{
pC1->f1();
}


通过指针pC1调用虚拟函数f1。仅仅看这段代码,你不会知道它调用的是那一个f1函数——C1::f1或C2::f1,因为pC1可以指向C1对象也可以指向C2对象。尽管如此编译器仍然得为在makeACall的f1函数的调用生成代码,它必须确保无论pC1指向什么对象,函数的调用必须正确。编译器生成的代码会做如下这些事情:

1). 通过对象的vptr找到类的vtbl。

2). 找到对应vtbl内的指向被调用函数的指针。

3). 调用第二步找到的的指针所指向的函数。

多继承与虚基类

多继承经常导致对虚基类的需求。没有虚基类,如果一个派生类有一个以上从基类的继承路径,基类的数据成员被复制到每一个继承类对象里,继承类与基类间的每条路径都有一个拷贝。而把基类定义为虚基类则可以消除这种复制。

虚基类是以什么方式消除这种复制的?

虚基类的实现经常使用指向虚基类的指针做为避免复制的手段。

例如考虑下面这幅图,我经常称它为“恐怖的多继承菱形”:



这里A是一个虚基类,因为B和C虚拟继承了它。使用一些编译器(特别是比较老的编译器),D对象会产生这样布局:



可以看到,通过虚继承的B类和C类中,分别有一个指向基类数据成员的指针,这样就避免了重复复制的问题。

运行时类型识别

RTTI能让我们在运行时找到对象和类的有关信息,所以肯定有某个地方存储了这些信息让我们查询。这些信息被存储在类型为type_info的对象里,你能通过使用typeid操作符访问一个类的type_info对象。

语言规范上这样描述:我们保证可以获得一个对象动态类型信息,如果该类型有至少一个虚函数。

一点思考:运用C++也不短时间了,这个知识感觉还是盲点,是类似JAVA/C#里面反射的东西吗?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 C++