虚指针存在证明及虚函数表

C++多态的实现原理是依赖虚指针来辨别具体使用家族类中的哪一个函数。以下就来证明虚指针的存在。
我们知道,指针的大小在一般情况下是4个字节,所以我们建立一个虚函数,再来计算该类的大小,便可以验证虚函数的存在。

代码如下:

#include <iostream>
using namespace std;

class A
{
public:
                 void print ()
                {

                }
private:
                 int a ;
};

class B
{
public:
                 virtual void print()
                {

                }
private:
                 int a ;
};

void main ()
{
                 cout << "sizeof(A)" << sizeof( A) << endl ;
                 cout << "sizeof(B)" << sizeof( B) << endl ;
                 system("pause" );
}

运行结果:

A类与B类的,唯一差别就是在B类中 print()变成了一个虚函数,实验结果看到B类却比A类多出了4个字节,那说明在B类中,编译器隐藏的添加了一个虚指针的成员变量。

接下来在验证,一个类中,有多个虚函数,会不会分配多个虚指针:

#include <iostream>
using namespace std;

class B
{
public:
                 virtual void print()
                {

                }
                 virtual void print2()
                {

                }
private:
                 int a ;
};

void main ()
{
                 cout << "sizeof(B)" << sizeof( B) << endl ;
                 system("pause" );
}

运行结果:

这就说明了,一个类中不管有几个虚函数,都只会生成一个虚指针变量。

这个虚指针变量实质上是指向一个虚函数表。我们先来看下什么是虚函数表。

虚函数表定义:

类的虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址。注意的是,编译器会为每个有虚函数的类创建一个虚函数表,该虚函数表将被该类的所有对象共享。类的每个虚成员占据虚函数表中的一行。如果类中有N个虚函数,那么其虚函数表将有N*4字节的大小。也就是说虚函数表是一块连续的内存,每一个虚成员,都会占据一块内存空间。

在平时设计代码是如果明确不需要使用虚函数,那就不要随便使用:

1 主要原因是,虚指针调用虚函数是在程序运行时进行的,所以需要通过寻址操作才能找到真正应该调用的函数,而普通成员函数是在编译时就确定了调用的函数,不需要寻址操作,因此在效率上,虚函数的效率要低很多。

2 其次,因为他会在虚函数表中多占据一块内存空间,浪费空间。

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

时间: 2024-11-14 11:16:45

虚指针存在证明及虚函数表的相关文章

c/c++: c++继承 内存分布 虚表 虚指针 (转)

http://www.cnblogs.com/DylanWind/archive/2009/01/12/1373919.html 前部分原创,转载请注明出处,谢谢! class Base { public:  int m_base; }; class DerivedA: public Base { public:  int m_derivedA; }; class DerivedB: public Base { public:  int m_derivedB; }; class DerivedC

C++内存分布 虚表 虚指针(非常重要)

C++内存分布 虚表 虚指针: class Base { public: int m_base; }; class DerivedA: public Base { public: int m_derivedA; }; class DerivedB: public Base { public: int m_derivedB; }; class DerivedC: public DerivedA, public DerivedB { public: int m_derivedC; }; 类结构图:

单继承与多继承中的虚函数表和虚函数指针

首先,我们了解一下何为单继承,何为多继承?? 单继承:一个子类只有一个直接父类. 多继承:一个子类有两个或多个直接父类. 单继承中的虚函数表分析: 示例程序: #include <iostream> using namespace std; typedef void(*FUNC)(); class Base { public: virtual void func1() { cout << "Base::func1()" << endl; } virt

C++虚函数表指针的值

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

C++学习 - 虚表,虚函数,虚函数表指针学习笔记

虚函数 虚函数就是用virtual来修饰的函数.虚函数是实现C++多态的基础. 虚表 每个类都会为自己类的虚函数创建一个表,来存放类内部的虚函数成员. 虚函数表指针 每个类在构造函数里面进行虚表和虚表指针的初始化. 下面看一段代码: // // main.cpp // VirtualTable // // Created by Alps on 15/4/14. // Copyright (c) 2015年 chen. All rights reserved. // #include <iostr

C++对象内存模型2 (虚函数,虚指针,虚函数表)

从例子入手,考察如下带有虚函数的类的对象内存模型: 1 class A { 2 public: 3 virtual void vfunc1(); 4 virtual void vfunc2(); 5 void func1(); 6 void func2(); 7 virtual ~A(); 8 private: 9 int m_data1, m_data2; 10 }; 11 12 class B : A { 13 public: 14 virtual void vfunc1();; 15 vo

虚函数指针和虚函数表

1 #include <iostream> 2 3 using namespace std; 4 5 class father 6 { 7 public: 8 father(int x):m_idata(x) 9 {} 10 11 virtual void show(int idata) 12 { 13 cout << "papa" << endl; 14 cout << idata-20 << endl; 15 } 16 v

深入剖析C++多态、VPTR指针、虚函数表

在讲多态之前,我们先来说说关于多态的一个基石------类型兼容性原则. 一.背景知识 1.类型兼容性原则 类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代.通过公有继承,派生类得到了基类中除构造函数.析构函数之外的所有成员.这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决.类型兼容规则中所指的替代包括以下情况: 子类对象可以当作父类对象使用 子类对象可以直接赋值给父类对象 子类对象可以直接初始化父类对象 父类指针可以直接指向子类对

虚函数表指针vptr的测试

类的虚函数调用是通过虚函数表实现的.所谓虚函数表,是编译器自动为一个带有虚函数的类生成的一块内存空间,其中存储着每一个虚函数的入口地址.由于函数的入口地址可以看成一个指针类型,因此这些虚函数的地址间隔为四个字节.而每一个带有虚函数类的实例,编译器都会为其生成一个虚函数指针——vptr,在类的对象初始化完毕后,它将指向虚函数表. 这个vptr指针将位于类对象的首部,即作为第一个成员变量,处于类对象代表的内存块的前四个字节中.为了便于理解和复习,在此将其内存结构以图示之. 查阅资料得知,C++标准并