仪器社区

C++虚表问题

7856xjgh 2017-10-02
请教一个问题,C++中从虚基类派生出来的类,如果原虚基类中的虚函数在该类中还是虚函数,那么系统会不会给这个派生类创建虚表?或者是只分配一个指针指向diyi次出现这些虚函数的基类的... 请教一个问题,C++中从虚基类派生出来的类,如果原虚基类中的虚函数在该类中还是虚函数,那么系统会不会给这个派生类创建虚表?或者是只分配一个指针指向diyi次出现这些虚函数的基类的虚表? 1楼的朋友谢谢你的回答 我喜欢结交你这样的有研究精神的朋友,你的分析很有研究价值,暂且先不讨论编译器的问题。 我从深入浅出MFC中找到虚表的相关知识,这个肯定不会有错,期待问题能够尽早彻底解决 深入浅出MFC: 1.每一个内涵虚函数的类,编译器都为它做出一个虚拟函数表,表中的每一个元素都指向一个虚函数的地址。 此外,编译器当然也会为类表加上一项成员函数,是一个指向该虚拟函数表的指针(常被称为vptr),每一个由此类别派生出来的类,都有这么一个vptr。 2.虚表以及这种间接呼叫方式。虚表的内容是依据类别中的虚函数声明次序--填入函数指针。派生类别会继承基础类别的虚表(以及所有其他可以继承的成员),当我们在派生类中改写虚函数时,虚表就受了影响;表中的元素所指的函数地址将不再是基类的函数地址,而是派生类的函数地址。 总结:通过深入浅出MFC的内容可以得知: 1,派生类要继承基类的虚表,而不只是说继承基类的虚表指针,所以可以判定,至少从理论上可以判定虚表是要拷贝的,而不是继续用父类虚表,而且多想想也应该可以理解,父类对象指针所指的虚表内容应该和子类不同,因为刚才有提到虚表函数的重定向。可能编译器做了某种优化,再研究
评论
全部评论
miaomiao342874
虚函数表是编译器用来实现多态的方法。一般来说,虚函数表是一个数组,数组的元素是虚函数的指针。每个对象都会有一个虚函数表,当在某个对象上调用虚函数时,通过查询这个表来获得继承层次中到底哪个函数被实际调用。
对于一个类如果有虚函数,就会在这个类中创建一个虚表,也就会产生一个虚指针指向这个虚表。
既然有一个指针指向了虚表,这个类派生后,在派生类中就不必再创建虚表,如果派生类还有自己的虚函数,那么只在派生类中创建该虚函数的一个虚表,产生一个指向该虚表的指针。
为每个类设置虚表,初始化虚指针,为虚函数调用插入代码都是自动发生的,不必担心这些。

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

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

public:
virtual void b(){};

};

int main()
{
cout< cout< }

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

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

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

在分析一个例子:
#include
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< cout< cout< }
这个直接继承的例子,在vc下,codeblocks下结果都为 8 12 16.

再看这个直接继承的例子:
#include
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< cout< cout< }
vc下河codeblocks下结果都为 4. 这两个程序说明,直接继承下,输出结果应当是本类所占的字节加父类数据成员所占字节,父类的虚指针所占字节没有加上。

加入虚继承后:
#include
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< cout< cout< }
这段代码,在codeblocks下g++编译运行结果为:8 16 24.
在vc6.0下编译运行结果为:8 20 32.
能够分析出codeblocks下的结果是本类加上父类的结果。vc下是 本类加父类后又加了4个字节。

但是这段代码:
#include
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< cout< cout< }
codeblocks下编译运行结果为 4 4 4.
vc下编译运行结果为:4 12 20.
从结果来看,vc下是 本类加父类后又加了4个字节。而codeblocks结果就不再是本类加父类的结果(这个有点迷茫)。
10 0 2017-10-03 0条评论 回复
您可能感兴趣的社区主题
加载中...
发布 评论