C++虚表问题

作者&投稿:示农 (若有异议请与网页底部的电邮联系)
C/C++编译器中虚表是如何完成的?~

编译器会搜集一个类的所有虚函数,并在编译时生成一个虚函数表。然后编译器实际上会在类的构造和析构函数中加一些代码来达到初始化虚表指针和改变虚表指针的目的。

就是加上virtual关键字的类成员函数,效果和纯虚函数有所差别:
1 定义了纯虚函数的类是抽象类,不能被实例化。而定义了虚函数的类可以。
2 定义了虚函数的基类指针调用虚函数时,如果指向派生类并且派生类覆盖定义了虚函数,那么会调用派生类的这个函数。否则调用基类的这个函数。
3 如果派生类覆盖定义了基类的函数(没有virtual),那么基类指针指向派生类的时候调用的依然是基类的函数。
class A{public:virtual int show(){}int func(){}};class B:public A{public:int func(){}int show(){}};int main(int argc, char const *argv[]){A * ptr = new B();ptr->func();//调用基类的funcptr->show();//调用派生类的showreturn 0;}这里面扯到一个多态问题,你自己去百度看看比较好。

对于一个类如果有虚函数,就会在这个类中创建一个虚表,也就会产生一个虚指针指向这个虚表。
既然有一个指针指向了虚表,这个类派生后,在派生类中就不必再创建虚表,如果派生类还有自己的虚函数,那么只在派生类中创建该虚函数的一个虚表,产生一个指向该虚表的指针。
为每个类设置虚表,初始化虚指针,为虚函数调用插入代码都是自动发生的,不必担心这些。

(我看到过虚继承下虚表问题的分析,直接继承下没看过,特此又分析了一下,修改)
#include<iostream>
using namespace std;
class A
{

public:
virtual void a(){};
};
class B:public virtual A
{

public:
virtual void b(){};

};

int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
}

对于这个程序,你大概是在vc6.0下运行的吧,在vc下结果是4和12。我用的编译器是g++,对于这段程序的结果确实都为4.

因编译器不同导致结果不同这个我倒是没注意,这样可以得出,对虚函数这里的处理机制和编译器也是有关的,g++编译器还是更符合新的标准。

把虚继承virtual去掉再运行,在codeblocks下,g++编译运行结果都为4. vc下编译运行结果也都为4.

在分析一个例子:
#include<iostream>
using namespace std;
class A
{
char j[3];
public:
virtual void a(){};
};
class B:public A
{
char k[3];
public:
virtual void b(){};

};
class C:public B
{
char m[3];
public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
这个直接继承的例子,在vc下,codeblocks下结果都为 8 12 16.

再看这个直接继承的例子:
#include<iostream>
using namespace std;
class A
{

public:
virtual void a(){};
};
class B:public A
{

public:
virtual void b(){};

};
class C:public B
{

public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
vc下河codeblocks下结果都为 4. 这两个程序说明,直接继承下,输出结果应当是本类所占的字节加父类数据成员所占字节,父类的虚指针所占字节没有加上。

加入虚继承后:
#include<iostream>
using namespace std;
class A
{
char j[3];
public:
virtual void a(){};
};
class B:public virtual A
{
char k[3];
public:
virtual void b(){};

};
class C:public virtual B
{
char m[3];
public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
这段代码,在codeblocks下g++编译运行结果为:8 16 24.
在vc6.0下编译运行结果为:8 20 32.
能够分析出codeblocks下的结果是本类加上父类的结果。vc下是 本类加父类后又加了4个字节。

但是这段代码:
#include<iostream>
using namespace std;
class A
{

public:
virtual void a(){};
};
class B:public virtual A
{

public:
virtual void b(){};

};
class C:public virtual B
{

public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
codeblocks下编译运行结果为 4 4 4.
vc下编译运行结果为:4 12 20.
从结果来看,vc下是 本类加父类后又加了4个字节。而codeblocks结果就不再是本类加父类的结果(这个有点迷茫)。

我只能提供这么多信息了~
如果你有更好的解释可以给我留言,相互学习~

虚函数表是编译器用来实现多态的方法。一般来说,虚函数表是一个数组,数组的元素是虚函数的指针。每个对象都会有一个虚函数表,当在某个对象上调用虚函数时,通过查询这个表来获得继承层次中到底哪个函数被实际调用。
对于一个类如果有虚函数,就会在这个类中创建一个虚表,也就会产生一个虚指针指向这个虚表。
既然有一个指针指向了虚表,这个类派生后,在派生类中就不必再创建虚表,如果派生类还有自己的虚函数,那么只在派生类中创建该虚函数的一个虚表,产生一个指向该虚表的指针。
为每个类设置虚表,初始化虚指针,为虚函数调用插入代码都是自动发生的,不必担心这些。

(我看到过虚继承下虚表问题的分析,直接继承下没看过,特此又分析了一下,修改)
#include<iostream>
using namespace std;
class A
{

public:
virtual void a(){};
};
class B:public virtual A
{

public:
virtual void b(){};

};

int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
}

对于这个程序,你大概是在vc6.0下运行的吧,在vc下结果是4和12。我用的编译器是g++,对于这段程序的结果确实都为4.

因编译器不同导致结果不同这个我倒是没注意,这样可以得出,对虚函数这里的处理机制和编译器也是有关的,g++编译器还是更符合新的标准。

把虚继承virtual去掉再运行,在codeblocks下,g++编译运行结果都为4. vc下编译运行结果也都为4.

在分析一个例子:
#include<iostream>
using namespace std;
class A
{
char j[3];
public:
virtual void a(){};
};
class B:public A
{
char k[3];
public:
virtual void b(){};

};
class C:public B
{
char m[3];
public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
这个直接继承的例子,在vc下,codeblocks下结果都为 8 12 16.

再看这个直接继承的例子:
#include<iostream>
using namespace std;
class A
{

public:
virtual void a(){};
};
class B:public A
{

public:
virtual void b(){};

};
class C:public B
{

public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
vc下河codeblocks下结果都为 4. 这两个程序说明,直接继承下,输出结果应当是本类所占的字节加父类数据成员所占字节,父类的虚指针所占字节没有加上。

加入虚继承后:
#include<iostream>
using namespace std;
class A
{
char j[3];
public:
virtual void a(){};
};
class B:public virtual A
{
char k[3];
public:
virtual void b(){};

};
class C:public virtual B
{
char m[3];
public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
这段代码,在codeblocks下g++编译运行结果为:8 16 24.
在vc6.0下编译运行结果为:8 20 32.
能够分析出codeblocks下的结果是本类加上父类的结果。vc下是 本类加父类后又加了4个字节。

但是这段代码:
#include<iostream>
using namespace std;
class A
{

public:
virtual void a(){};
};
class B:public virtual A
{

public:
virtual void b(){};

};
class C:public virtual B
{

public:
virtual void c(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
codeblocks下编译运行结果为 4 4 4.
vc下编译运行结果为:4 12 20.
从结果来看,vc下是 本类加父类后又加了4个字节。而codeblocks结果就不再是本类加父类的结果(这个有点迷茫)。


C++虚表问题
对于一个类如果有虚函数,就会在这个类中创建一个虚表,也就会产生一个虚指针指向这个虚表。既然有一个指针指向了虚表,这个类派生后,在派生类中就不必再创建虚表,如果派生类还有自己的虚函数,那么只在派生类中创建该虚函数的一个虚表,产生一个指向该虚表的指针。为每个类设置虚表,初始化虚指针,为...

C++虚函数表的问题!(看一段代码,高分悬赏)
&b是取出对象的地址,(int*)(&b)是将该地址转换为整形指针,就是对象虚表数组的首地址,*(int*)(&b)是将取出虚表数组的第一项,就是第一个虚函数的首地址,(int*)*(int*)(&b)就是将该地址转换为整形指针。问题二:void*不是一个指向对象类型的指针(int*,long*都是),所以你向...

oracle的一个问题
虚表(dual)是oracle提供的最小的工作表,它仅包含一行一列。对于虚表(dual)来说,其中的列往往是不相关的或无关紧要的。如果不理解上面的话,就把dual当做是一张类似常量池 的表。你可以从中取出任何常量。例如,select sysdate from dual 就是取出当前系统时间 select 1 from dual 取出1 等等 ...

为什么这个C++类的虚表里只有一个方法呢?求教大神...
你这个整体思路没有错,只是有些小问题(1、成员函数一定要和对象相对, 2、循环最后应该是加i吧,3、while (vtb != NULL)是没有用的,vtb==null的概率极小)。但不知道为什么你会得到这样的结果,可能是编译器的原因吧,你可以反汇编看一下。

游戏悍将500w是不是虚表
不是。游戏悍将的电源从来没有出现过功率虚标的问题,而红紫银效RP500M电源额定500W输出还对游戏玩家的配置特点进行了优化。游戏悍将红警500电源拥有450W的额定功率,并采用单路+12V输出设计,能够良好满足主流独显游戏平台对于电力的要求,同时有着运行稳定、节能效果好等优点。

...吐槽内容大部分系谣言,学生的吐槽真的徒有虚表吗?
事情闹大了以后这所学校也并没有给出一个合理的解决办法,也许学生的话语当中是有一些夸大的成分,但是不能够说明这些事情不是真实存在的。假如说学校没有做出这样的事情,学生也没有必要去在网络上面抹黑自己的母校。因此希望学校还是能够好好的解决学生们所提出来的这些问题,不要让学生感到失望。

帮我看看这电源是不是虚表,500w电源最大输出才420w
这电源的电压出入太大了。500W默认电源实际使用才420W ,正常都是480W到520W之间才算合格产品。正常上下20W才是正常的。这电源有点虚。

三星电池容量太低 2100毫安的可能也是虚表的 网上有的买5000多毫安的...
电池电芯都是标准的,一定大小的电池只能包装进去那么多的电芯,即使牺牲结构和散热标准,能加大的空间也是非常有限的。原装电池2100,兼容电池能做到2300左右就是极限了,再大是不可能的。所谓5000多的已经不是叫做虚标而是应该叫乱标了。

C++中虚继承和一般的继承有什么不同
D中包含两份Class A的对象。此时就会出现访问歧义的情况。虚继承就可以避免上面的情况。Class A的数据会被放到虚表中。Class D会识别到来自Class B和C的虚表,然后将两者合并。所以回到本件问题,问题中的Class B就会包含一份虚函数表指针,一份虚类指针。也就是sizeof(B)的结果是8。

加盟e修鸽付了加盟费,可是公司没有兑现承诺,徒有虚表,属不属于商业欺诈...
可以的,但是不会构成欺诈罪的。

商城县17236172217: C++虚表问题 -
茆耍汤尼: 虚函数表是编译器用来实现多态的方法.一般来说,虚函数表是一个数组,数组的元素是虚函数的指针.每个对象都会有一个虚函数表,当在某个对象上调用虚函数时,通过查询这个表来获得继承层次中到底哪个函数被实际调用. 对于一个类如...

商城县17236172217: C/C++编译器中虚表是如何完成的? -
茆耍汤尼: 每一个类都会有一张虚函数表的,当然了,这个类必须继承了或者有虚函数. 并且这个虚函数表仅仅保存的是函数的地址. 例如父类有两个虚函数A和B,地址分别是0001和0002.此时父类的虚函数表就是8个字节. 然后子类继承了父类之后,子类也有一个虚函数表.也是8个字节. 如果子类没有改写父类的虚函数,那么子类的虚函数表和父类的虚函数表是一样的. 如果子类改写了虚函数,那么就发生变化了.例如子类修改了父类中的两个虚函数,那么子类中的虚函数表分别保存了0003和0004两个地址.这就是虚函数的作用,如果你不修改父类的虚函数表,那么你就是调用父类的虚函数. 如果你重载了,那么就调用新的虚函数表中的地址来查找重载之后的函数.

商城县17236172217: C++虚表问题
茆耍汤尼: 对于一个类如果有虚函数,就会在这个类中创建一个虚表,也就会产生一个虚指针指向这个虚表. 既然有一个指针指向了虚表,这个类派生后,在派生类中就不必再创建虚表,如果派生类还有自己的虚函数,那么只在派生类中创建该虚函数的一...

商城县17236172217: 一个关于C++虚函数表的问题(求高手解释) -
茆耍汤尼: ——请解释&b+i对应函数的位置,并简单介绍虚函数表.感觉前面问了一个学术问题,后面则是在求做作业... 总觉得如果你看得懂这个代码,应该不会不知道虚函数表这个东西吧...虚函数表是编译器用来实现多态的方法.一般来说,虚函数表是...

商城县17236172217: c++中,什么情况下虚表指针会是0 -
茆耍汤尼: 这个一般是abi不兼容,开放的头文件中某类有虚函数,又被开放的另外一个类继承了,前面的类加了个虚函数,导致虚表offset变了,然后用户代码继承了这个类,导致有虚函数找不到了,所以是0,详细可咨询远标

商城县17236172217: C++中虚函数、虚表指针的问题 -
茆耍汤尼: 首先用gcc编译,gcc是c编译器,不会考虑多态的问题. 使用虚函数实际上就是利用虚函表实现确定函数的调用,在每个对象的存储空间中它会多出一定的存储空间,用于保存虚函数表的内存地址,所以你看到的不是12而是16,那4个字节用于...

商城县17236172217: C++虚表指针问题 -
茆耍汤尼: eat()函数需为虚函数,在Animal类声明为 virtual eat();你的Dog *d = new Dog //新建一个Dog对象d,然后将对象d指针赋给父类指针,通过父类指针a实现对d对象的动态调用··虚函数表地址 (int*)(&a)虚函数表第一个函数地址 (int*)*(int*)(&a)在这里,如果你的虚函数表第一个函数是eat的话,可以这样调用:typedef void(Fun*)(void);Fun pFun=NULL;pFun = (Fun)*((int*)*(int*)(&a)+0);//0表示虚函数表的偏移量 0-->第一个函数pFun();//这里就会调用eat()函数··

商城县17236172217: C++虚函数怎么理解? -
茆耍汤尼: C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术.所谓泛型技术,...

商城县17236172217: 到底C++多继承里几个虚表 -
茆耍汤尼: 不管多少次继承, 都只有一个虚函数表.这个虚函数表里面可以有多个节点.但不管多少节点, 入口都只有一个, 就是虚表地址.

商城县17236172217: C++标准中,虚表指针在类的内存结构位置没有规定 -
茆耍汤尼: 为了保证正确取到虚函数的偏移量,C++标准规定编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置.

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网