C++虚指针在构造函数的什么阶段初始化(yahoo面试题)

ywfscu 2005-01-11 05:55:54
为什么不能在构造函数里面调用虚函数??
...全文
776 26 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
yjh1982 2005-01-12
  • 打赏
  • 举报
回复
构造函数的用户代码执行之前会先设自己所属类的虚表.

假设B是A的子类.
B的构造肯定会调用A的构造.
A的构造设A虚表.所以A的构造中调用的虚函数不会指到B的实现去
A的构造完成后会到B的构造
在B的构造函数的用户代码执行之前先设B虚表.


如是
xue23 2005-01-12
  • 打赏
  • 举报
回复
问题是不是丢了什么前提
nicknide 2005-01-12
  • 打赏
  • 举报
回复
hongjun_han(han):什么也没有吗?没有显示吗?没有显示就奇怪了,你是什么编译器跑的?我用VC和DEV都是一样的结果啊……
hongjun_han 2005-01-12
  • 打赏
  • 举报
回复
这个顺序在 inside the c++ object model里面很明确
先虚基类
然后其他基类
然后 虚函数指针
然后 对象成员构造函数,如果不在 成员列表中
然后 成员列表
然后里面的其他代码
hongjun_han 2005-01-12
  • 打赏
  • 举报
回复
跑完你这个程序也没什么呀,有什么问题。不知道你要说什么
#include <stdio.h>
#include <iostream>
using namespace std;
class B
{
public:
B(void){P();}
virtual void P(void){std::cout<<"This is B"<<std::endl;}
};

class D
{
public:
D(void){P();}
virtual void P(void){std::cout<<"This is D"<<std::endl;}
};


void main()
{
B b;
D d;

}
playmud 2005-01-12
  • 打赏
  • 举报
回复
楼上的例子不是当的。
实际上在运行B::B()之前,A:A()已经执行了。应该说B已经实例话了。你的sizeof(B)当然是正确的了。
我不明白vptr初始化是什么意思。
其实虚函数实现主要的功能是功能的本地化作用。就是替代父类的功能。而构造函数的作用是实例化作用,主要是对类成员变量的始初化。二者的作用应该是不相干了。
----------------------------------------------------------------
怎么不当了??
实际上在运行B::B()之前,A:A()已经执行了,本来就该如此啊。晕。
vptr的初始化是在构造函数刚开始,初始化参数列表之前进行的,然后才是调用你构造函数里面自己写的东东。
nicknide 2005-01-12
  • 打赏
  • 举报
回复
所以按照我楼上的例子来看,vtable并不是一次就初始化完成的,而是分阶段来逐步补充完善的:不过开了优化之后是什么结果就不清楚了,但是绝对不要依赖优化来达到你代码的正确性!(当然,在这个例子中,开了优化的结果应该还是一样,呵呵,因为vtable在中间也使用到了,因此必须分布填充vtable(在你自己的对应的构造函数开始运做前,填充vtable)
nicknide 2005-01-12
  • 打赏
  • 举报
回复
构造函数最好不要用多态:
class B
{
B(void){P();}
virtual void P(void){std::cout<<"This is B"<<std::endl;}
};

class D
{
D(void){P();}
virtual void P(void){std::cout<<"This is D"<<std::endl;}
};

楼主跑完这个程序就明白了的。
xue23 2005-01-12
  • 打赏
  • 举报
回复
楼上的例子不是当的。
实际上在运行B::B()之前,A:A()已经执行了。应该说B已经实例话了。你的sizeof(B)当然是正确的了。
我不明白vptr初始化是什么意思。
其实虚函数实现主要的功能是功能的本地化作用。就是替代父类的功能。而构造函数的作用是实例化作用,主要是对类成员变量的始初化。二者的作用应该是不相干了。
playmud 2005-01-12
  • 打赏
  • 举报
回复
编译器正式为了能够在构造函数里面调用正确的虚函数,所以才会在构造函数刚开是,初始化参数列表之前对vptr进行初始化。而不会在构造函数结尾。
#include <iostream>
using namespace std;
class A
{
public :
A()
{
p() ;
}
virtual void p() {cout<<"A:"<<sizeof(A)<<endl;};
};
class B : public A
{
public:
int i;
B():i(10)
{
p();
}
virtual void p(){cout<<"B:"<<sizeof(B)<<endl;} ;
};
int main()
{
B b;
system("pause");

}

看看是否可以得到B的大小!初始化vptr而已。
hchinside 2005-01-12
  • 打赏
  • 举报
回复
http://www.waterbbs.com/dispbbs.asp?boardID=5&ID=1114
wim 2005-01-12
  • 打赏
  • 举报
回复
Member functions can be called from a constructor (or destructor) of an abstract class


补充一下....
wim 2005-01-12
  • 打赏
  • 举报
回复
the effect of making a virtual call to a pure virtual function directly or indirectly for the object being created from such a constructor is underfined.

Copy from <<Cpp Std Document>> 196/776
HNET 2005-01-12
  • 打赏
  • 举报
回复
技术上可行 但逻辑上最好不要这么做。在构造函数完成之前,对象尚未达到一个正确的一致的状态,而虚函数的行为有时动态的由类型系统确定的,所以一般不这么做。但是,如果能保证状态正确性,可以使用,例如可以在构造函数中应用模板方法模式。:)
dhy311 2005-01-12
  • 打赏
  • 举报
回复
14.8.2 虚函数在构造函数中的行为
构造函数调用层次会导致一个有趣的两难选择。试想;如果我们正在构造函数中并且调用
虚函数,那么会发生什么现象呢?对于普通的成员函数,虚函数的调用是在运行时决定的,这
是因为编译时并不能知道这个对象是属于这个成员函数所在的那个类,还是属于由它派生出来
的类。于是,我们也许会认为在构造函数中也会发生同样的事情。
然而,情况并非如此。对于在构造函数中调用一个虚函数的情况,被调用的只是这个函数
的本地版本。也就是说,虚机制在构造函数中不工作。
这个行为有两个理由。在概念上,构造函数的工作是把对象变成存在物。在任何构造函数
中,对象可能只是部分被形成—我们只能知道基类已被初始化了,但不知道哪个类是从这个
基类继承来的。然而,虚函数是“向前”和“向外” 进行调用。它能调用在派生类中的函数。
如果我们在构造函数中也这样做,那么我们所调用的函数可能操作还没有被初始化的成员,这
将导致灾难的发生。
第二个理由是机械的。当一个构造函数被调用时,它做的首要的事情之一是初始化它的
V P T R。因此,它只能知道它是“当前”类的,而完全忽视这个对象后面是否还有继承者。当
编译器为这个构造函数产生代码时,它是为这个类的构造函数产生代码- -既不是为基类,也不
是为它的派生类(因为类不知道谁继承它)。所以它使用的V P T R必须是对于这个类的V TA B L E。
而且,只要它是最后的构造函数调用,那么在这个对象的生命期内, V P T R将保持被初始化为
指向这个V TA B L E。但如果接着还有一个更晚派生的构造函数被调用,这个构造函数又将设置
V P T R指向它的V TA B L E,等等,直到最后的构造函数结束。V P T R的状态是由被最后调用的构
造函数确定的。这就是为什么构造函数调用是从基类到更加派生类顺序的另一个理由。
但是,当这一系列构造函数调用正发生时,每个构造函数都已经设置V P T R指向它自己的
V TA B L E。如果函数调用使用虚机制,它将只产生通过它自己的V TA B L E的调用,而不是最后
的V TA B L E(所有构造函数被调用后才会有最后的V TA B L E)。另外,许多编译器认识到,如
果在构造函数中进行虚函数调用,应该使用早捆绑,因为它们知道晚捆绑将只对本地函数产生
调用。无论哪种情况,在构造函数中调用虚函数都没有结果
dhy311 2005-01-12
  • 打赏
  • 举报
回复
不可以,构造函数是的调用顺序是从子类-》父类,
虚拟函数是调用最后最后定义该虚拟函数的,
这样就存在着矛盾
Tdxdy 2005-01-11
  • 打赏
  • 举报
回复
不可以
FireEmissary 2005-01-11
  • 打赏
  • 举报
回复
构造函数的结尾才初始化.

能在构造函数里面调用虚函数,但不是你要的效果
jasic2002 2005-01-11
  • 打赏
  • 举报
回复
这个问题是有点复杂。从语法上说这样使用是可以,但是在实际应用可能会产生问题
。比如说:
class A
{
prublic :
A()
{
p() ;
}
virtual void p() ;
}
class B : public A
{
public:
B()
{...
}
virtual void p() ;
}

在上述例子中,如果创建B对象,这时在A的构造器中原本希望调用B的P
函数,但是实际当中是调用了A的P函数。而这种错误是不易察觉的。所以尽量避免在构造函数中使用function with virtual
liem 2005-01-11
  • 打赏
  • 举报
回复
当产生公有派生类时,构造派生类实例需要调用基类构造函数,此时派生类对象尚未建立,调用虚函数会有问题吗?

我想不会有问题的。
虚函数是在用基类指针(或引用)指向派生类对象时起作用,在基类的构造函数中调用虚函数并不存在用基类指针指向派生类对象问题。
加载更多回复(6)

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧