C++ 关于类与对象在虚函数表上唯一性问题 浅析

【摘要】

很多教材上都有介绍到虚指针、虚函数与虚函数表,有的说类对象共享一个虚函数表,有的说,一个类对象拥有一个虚函数表;还有的说,无论用户声明了多少个类对象,但是,这个VTABLE虚函数表只有一个;也有的在说,每个具有虚函数的类的对象里面都有一个VPTR虚函数指针,这个指针指向VTABLE的首地址,每个类的对象都有这么一种指针。今天,我们就来解决这个问题,同一个类的不同对象,是不是拥有“相同”的虚函数表,这个相同是物理上的相同(内存地址)还是逻辑上的相同(数据结构)。本文现详述如下!

【正文】

虚指针:每个含有虚方法(虚函数)对象里有虚表指针,指向虚表。

虚函数表:虚函数表是顺序存放虚函数地址的,虚表是顺序表,表里存放了虚函数的地址。

C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。

【代码示例】

#include <iostream>
using namespace std;

class Base {
public:
	virtual void f() { cout << "Base::f" << endl; }
	virtual void g() { cout << "Base::g" << endl; }
	virtual void h() { cout << "Base::h" << endl; }

};
typedef void(*Fun)(void);

int main()
{
	Fun pFun = NULL;
	Base obj_1,obj_2;
	// obj_1 虚函数表 — 第一个函数
	pFun = (Fun)*((int*)*(int*)(&obj_1));
	pFun();
	pFun = (Fun)*(((int*)*(int*)(&obj_1))+1);
	pFun();
	// 输出 虚函数表地址 与 虚函数表元素 的值
	cout << "obj_1 虚函数表地址:" << (int*)(&obj_1) << endl;
	cout << "obj_2 虚函数表地址:" << (int*)(&obj_2) << endl;
	cout << "obj_1 虚函数表 — 第一个函数地址:" << (int*)*(int*)(&obj_1) << endl;
	cout << "obj_2 虚函数表 — 第一个函数地址:" << (int*)*(int*)(&obj_2) << endl;
	return 0;
}
/*
输出 :
Base::f
Base::g
obj_1 虚函数表地址:0018FF40
obj_2 虚函数表地址:0018FF3C
obj_1 虚函数表 — 第一个函数地址:0046F0AC
obj_2 虚函数表 — 第一个函数地址:0046F0AC
Press any key to continue
*/

【结论】

不同对象虚函数表表中元素是相等的,逻辑上是一样的,存放的都是类中虚函数的地址;

不同对象虚函数表的内存地址是不一样,物理上是不一样的,一个对象是一个新的表。

【相关推荐】

详见:C++ 虚函数表解析

详址:http://blog.csdn.net/haoel/article/details/1948051#comments

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-30 23:03:53

C++ 关于类与对象在虚函数表上唯一性问题 浅析的相关文章

C++类成员空间分配和虚函数表

最近在自学python,看到继承和类,就顺便复习了C++的类和继承等方面的知识. 先看Base基类 class Base { private: virtual void display() { cout<<"Base display()"<<endl; } void say(){ cout<<"Base say()"<<endl; } public: virtual void func(){cout <<

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr)、C++对象模型

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr).C++对象模型 一.虚函数表指针(vptr)及虚基类表指针(bptr) C++在布局以及存取时间上主要的额外负担是由virtual引起的,包括: virtual function机制:用以支持一个有效率的"执行期绑定": virtual base class:用以实现多次在继承体系中的基类,有一个单一而被共享的实体. 1.虚函数表指针 C++中,有两种数据

C++入门学习——虚函数表介绍

多态 多态是指使用相同的函数名来访问函数不同的实现方法,可以简单概括为"一种接口,多种方法". C++支持编译时多态(也叫静态多态)和运行时多态(也叫动态多态),运算符重载和函数重载就是编译时多态,而派生类和虚函数实现运行时多态. 静态多态与动态多态的实质区别就是函数地址是早绑定还是晚绑定.如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态多态(编译时多态),就是说地址是早绑定的.而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定,是

C++ Daily 《5》----虚函数表的共享问题

问题: 包含一个以上虚函数的 class B, 它所定义的 对象是否共用一个虚函数表? 分析: 由于含有虚函数,因此对象内存包含了一个指向虚函数表的指针,但是这个指针指向的是同一个虚函数表吗? 实验如下: 结论: 结果表面,同一个类的所有对象,都共享同一个虚函数表. 派生问题: 派生类 和 基类是否共享同一个虚函数表呢? C++ Daily <5>----虚函数表的共享问题,布布扣,bubuko.com

C++虚函数表指针的值

前段时间在软件编写过程中碰到一个问题,顺便将感想写一下,虽然不知道是否随编译器的实现而异,但约束一下自己写代码的习惯总没错. 基类虚函数表指针值的变化 若基类中含有虚函数,当创建派生类对象时,虚函数表指针的值在进入派生类构造函数的函数体时会被修改为指向派生类新创建的虚函数表.当基类析构函数被调用时,虚函数表指针的值会被修改为指向基类创建的虚函数表,这样做是为了防止在基类析构函数中访问可能被释放了的派生类的那部分内存(尤其重要).一旦派生对象调用了基类析构函数,则所有指向该派生对象的基类指针都会失

C++之虚函数表

本文引自:http://songlee24.github.io/blog/2014/09/02/c-plus-plus-jin-jie-zhi-xu-han-shu-biao/ C++通过继承(inheritance)和虚函数(virtual function)来实现多态性.所谓多态,简单地说就是,将基类的指针或引用绑定到子类的实例,然后通过基类的指针或引用调用实际子类的成员函数(虚函数).本文将介绍单继承.多重继承下虚函数的实现机制. 一.虚函数表 为了支持虚函数机制,编译器为每一个拥有虚函数

对C++虚函数、虚函数表的简单理解

一.虚函数的作用 以一个通用的图形类来了解虚函数的定义,代码如下: #include "stdafx.h" #include <iostream> using namespace std; class Graph { protected: double x; double y; public: Graph(double x,double y) { this->x=x; this->y=y; } virtual void showArea() { cout<

C++多态篇3——虚函数表详解之多继承、虚函数表的打印

在上上一篇C++多态篇1一静态联编,动态联编.虚函数与虚函数表vtable中,我最后简单了剖析了一下虚函数表以及vptr. 而在上一篇文章C++多态篇2--虚函数表详解之从内存布局看函数重载,函数覆盖,函数隐藏中我详细介绍了虚函数的函数重载,函数覆盖以及函数隐藏的问题,其实在那一篇文章中,对单继承的虚函数已经做了十分详细的解答了,如果对前面有兴趣的人可以先看一下那篇文章. 在这一篇中,我会具体的分析一下在不同继承中(单继承,多继承)关于虚函数表在内存中的布局以及如何打印虚函数表.但是有关在虚继承

C++多态篇2——虚函数表详解之从内存布局看函数重载,函数覆盖,函数隐藏

上一篇C++多态篇1一静态联编,动态联编.虚函数与虚函数表vtable中,我在最后分析了虚函数与虚函数表的内存布局,在下一篇详细剖析虚函数及虚函数表的过程中,我发现有关函数重载,函数覆盖,函数重写和函数协变的知识也要理解清楚才能对虚函数表在内存中的布局,对派生类的对象模型以及对多态的实现有更深的理解. 所以这一篇我作为一篇过渡篇,也同时对我以前写过的一篇博文进行一个收尾.在C++继承详解之二--派生类成员函数详解(函数隐藏.构造函数与兼容覆盖规则)文章中,我对函数覆盖,重载,重写提了一下,但是没