This behavior makes sense for two reasons. Conceptually, the constructor’s job is to bring the object into existence (which is hardly an ordinary feat). Inside any constructor, the object may only be partially formed – you can only know that the base-class objects have been initialized, but you cannot know which classes are inherited from you. A virtual function call, however, reaches “forward” or “outward” into the inheritance hierarchy. It calls a function in a derived class. If you could do this inside a constructor, you’d be calling a function that might manipulate members that hadn’t been initialized yet, a sure recipe for disaster. The second reason is a mechanical one. When a constructor is called, one of the first things it does is initialize its VPTR. However, it can only know that it is of the “current” type. The constructor code is completely ignorant of whether or not the object is in the base of another class. When the compiler generates code for that constructor, it generates code for a constructor of that class, not a base class and not a class derived from it (because a class can’t know who inherits it). So the VPTR it uses must be for the VTABLE of that class. The VPTR remains initialized to that VTABLE for the rest of the object’s lifetime unless this isn’t the last constructor call. If a more-derived constructor is called afterwards, that constructor sets the VPTR to its VTABLE, and so on, until the last constructor finishes. The state of the VPTR is determined by the constructor that is called last. This is another reason why the constructors are called in order from base to most-derived.只想说:中国程序员都TMD太牛X!!!
我觉得这个问题主要牵涉到c++的继承的问题。
我认为结果应该是:
Y::foo
X::foo
赫赫,是吗?因为在构建class Y的对象的时候,编译器寻找class Y的构造函数,找不到,所以向上查找起伏类的构造函数,即调用class X的构造函数,同样的道理,调用foo(),所以print出Y::foo,然后调用bar()方法,由于当前类没有实现所以利用父类的bar()方法,所以print 出X::foo,
ok?
class X
{
public:
X() {
foo();
bar();
}void bar() {
foo();
}virtual void foo() {
printf("X::foo\n");
}
};class Y: public X
{
public:
virtual void foo() {
printf("Y::foo\n");
}
};void main()
{
new Y();
}
http://codeguru.earthweb.com/cgi-bin/bbs/wt/showpost.pl?Board=CSharp&Number=939&page=0&view=collapsed&sb=5
1. baseclass constructor( )
2. copy vfptr
(beging ur code)
3.early binding callees
X:foo()
X:foo()
Y:foo()
X:foo()
构造函数中是编译绑定。
X:foo
X:foo
原因与Kevin_qing(Kevin)观点相同。
X::foo
这是很明显的啊,new Y()要调用本身和父类的构造函数,而其父类的
X() {
foo();
bar();
}
就是prinft两次x::foo啊。还有,你程序中声明的虚函数没必要吧?
x::foo()
x::foo()
类y中无构造函数。
所以向上查找。从而得出以上结果
结果好象应该和楼上的几位兄台说的是::foo
不过,我个人觉得好象是:
Y::foo
Y::foo
没有调试过,不知正确否
hoho
classq 前加public也就算了,c++在java平台是什么时候可以编译的?java中能有不属于
任何类的main方法吗?实在是不懂
X:foo
X:foo
实际上涉及到了虚构造函数的概念,在生成基类的时候,子类还没有生成,所以虚机制根本还没有起作用
结果是肯定的,要真的不相信的话,
我在VC++6上编译过了,
--------------------Configuration: testvirtul - Win32 Debug--------------------
Compiling...
testvirtual.cpp
Linking...testvirtual.exe - 0 error(s), 0 warning(s)输出为:
X::foo
X::foo
Press any key to continue
X:foo
X:foo
至于java, C#,C++中的不同写法我想大家都很明白,不必要全部要我写出来吧。
其实下面的帖子更加详细,相信大家能明白我的本意。---http://codeguru.earthweb.com/cgi-bin/bbs/wt/showpost.pl?Board=CSharp&Number=939&page=0&view=collapsed&sb=5
X::foo
X::foo
因为Class Y中并没有自己的构造函数,但它继承了Class X,所以语句new Y()实际上就是调用Class X的构造函数---X()。
#include <stdio.h>class X
{
public:
X()
{
foo();
bar();
}
void bar()
{
foo();
} virtual void foo()
{
printf("X::foo\n");
}
};class Y: public X
{
public:
virtual void foo()
{
printf("Y::foo\n");
}
};void main()
{
new Y();
}结果应该是:
X::foo
X::foo
类构造时首先调用基类的构造函数然后再调用自己的构造函数
由于是虚函数,所以函数指针会指向正确的类(在此是基类X)
你可以给类Y加同样的构造函数如:
X()
{
foo();
bar();
}
然后再运行你就明白了
还可以去掉virtual关键字试一下
//hello.cpp
#include <afxwin.h>
class CHelloApp : public CWinApp
{ public:
virtual BOOL InitInstance();
};
CHelloApp HelloApp;
class CHelloWindow : public CFrameWnd
{
CStatic* cs;
public:
CHelloWindow();
};
BOOL CHelloApp::InitInstance()
{
m_pMainWnd = new CHelloWindow();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
CHelloWindow::CHelloWindow()
{
Create(NULL, "Hello World!", WS_OVERLAPPEDWINDOW, CRect(0,0,200,200));
cs = new CStatic();
cs->Create("hello world", WS_CHILD|WS_VISIBLE|SS_CENTER, CRect(50,80,150,150),this);
}
InitInstance()是在AfxWinMain(MFC的WinMain人口)里被直接调用的,而不是在CWinApp的构造函数中。
在Y的构造函数中,因为我们没有给出自己定义的default ctor,而Y又是从一个有着default ctor的class X中继承下来的。所以C++会为我们产生一个Y的default ctor,它的实现只是C++为了满足自己的编译条件。对于父类有default ctor的情况下,生成的default ctor的代码是先调用父类的default ctor(父类的ctor肯定要被调用,有时可以显式的调用-通过initialize list,有时为隐式调用,如我们现在讨论的情况),如果类中还含有带有default ctor的member的话,则生成的default ctor还将调用这些member的default ctor(在父类的之后,如果有多个这样的member,则它们的default ctor调用顺序以它们的宣告顺序一样)。
一个类的构造函数的大致流程为,先分配容纳该对象的内存给它,然后再配置这块内存,即在它上面调用构造代码
如果有virtual的话则生成其vtbl(如果有上面说的情况,则先生成父类及member对象(包括构造出它们自己的vtbl来)),
然后调用我们写在ctor中的代码通过这种情况,我们就可以知道得到这样的输出是必然的了:)
X::foo
X::foo
KAO!
不难吧!
X::foo()
X::foo()
开始一看你的标题还真有点不自信了,不过从这道题我还是悟出了一个道理;那就是一定要自信;)
The second reason is a mechanical one. When a constructor is called, one of the first things it does is initialize its VPTR. However, it can only know that it is of the “current” type. The constructor code is completely ignorant of whether or not the object is in the base of another class. When the compiler generates code for that constructor, it generates code for a constructor of that class, not a base class and not a class derived from it (because a class can’t know who inherits it). So the VPTR it uses must be for the VTABLE of that class. The VPTR remains initialized to that VTABLE for the rest of the object’s lifetime unless this isn’t the last constructor call. If a more-derived constructor is called afterwards, that constructor sets the VPTR to its VTABLE, and so on, until the last constructor finishes. The state of the VPTR is determined by the constructor that is called last. This is another reason why the constructors are called in order from base to most-derived.只想说:中国程序员都TMD太牛X!!!
希望大家在回答前先仔细的,全面的考虑清楚后再发言。
我很赞同bgsn的话:“不是说真是水平有多高,而是不够谦虚严谨,骄傲自大!!!”