Created
July 10, 2012 12:42
-
-
Save hpcx82/3083031 to your computer and use it in GitHub Desktop.
test the object construction sequence
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
using namespace std; | |
class Base | |
{ | |
public: | |
Base() {cout << "Base constructor called" << endl;} | |
}; | |
class Base1: virtual public Base | |
{ | |
public: | |
Base1() {cout << "Base1 constructor called" << endl;} | |
}; | |
class Base2: virtual public Base | |
{ | |
public: | |
Base2() {cout << "Base2 constructor called" << endl;} | |
}; | |
class Derived1: public Base1 | |
{ | |
public: | |
Derived1() {cout << "Derived1 constructor called" << endl;} | |
}; | |
class Derived2: public Base2 | |
{ | |
public: | |
Derived2() {cout << "Derived2 constructor called" << endl;} | |
}; | |
class BaseVirtualFunc | |
{ | |
public: | |
BaseVirtualFunc() | |
{ | |
cout << "BaseVirtualFunc constructor called" << endl; | |
virtual_foo(); | |
} | |
virtual void virtual_foo() {cout << "BaseVirtualFunc::virtual_foo called" << endl;} | |
}; | |
class TheMember | |
{ | |
public: | |
TheMember() | |
{ | |
cout << "TheMember constructor called: default" << endl; | |
} | |
TheMember(int i) | |
{ | |
cout << "TheMember constructor called:" << i << endl; | |
} | |
TheMember(BaseVirtualFunc* virt) | |
{ | |
cout << "TheMember constructor called: BaseVirtualFunc" << endl; | |
virt->virtual_foo(); | |
} | |
}; | |
class TheObject: public BaseVirtualFunc, public Derived1, public Derived2 | |
{ | |
private: | |
TheMember member0; | |
TheMember member1; | |
TheMember member2; | |
TheMember member3; | |
public: | |
TheObject(): | |
member3(3), member2(2), member0(this) | |
{ | |
cout << "TheObject constructor called" << endl; | |
} | |
virtual void virtual_foo() {cout << "TheObject::virtual_foo called" << endl;} | |
}; | |
int main() | |
{ | |
TheObject obj; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
一个复杂的C++对象构造,大概可以分为4步 - 这里复杂是指有多重继承,虚继承,基类有虚函数, 以及有类成员等等。 | |
1. 调用基类构造函数 - 由深到浅,由左至右, 如有虚拟继承,虚基类构造函数最先调用 | |
2. 子类vptr初始化 | |
3. 成员初始化 - 不管初始化列表中的顺序,也不管是否出现在初始化列表中,一律按照声明次序 | |
4. 构造函数体 | |
按照此顺序,把下面输出归类: | |
1. 调用基类构造函数 - 由深到浅,由左至右, 如有虚拟继承,虚基类构造函数最先调用 | |
Base(virtual) constructor called | |
PolyBase constructor called | |
PolyBase::virtual_foo called | |
Base1 constructor called | |
Derived1 constructor called | |
Base2 constructor called | |
Derived2 constructor called | |
2. 子类vptr初始化 - 这里通过在基类构造函数PolyBase::PolyBase()和子类第一个初始化成员TheMember(PolyBase* virt)的构造函数中调用虚函数virtual_foo,可以看到调用了不同的虚函数实现,从而可以证明vptr的初始化是在基类构造函数之后,子类成员初始化之前。 | |
TheMember constructor called: PolyBase | |
TheObject::virtual_foo called | |
3. 成员初始化 - 不管初始化列表中的顺序,也不管是否出现在初始化列表中,一律按照声明次序 | |
TheMember constructor called: default | |
TheMember constructor called:2 | |
TheMember constructor called:3 | |
4. 构造函数体 | |
TheObject constructor called |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Base(virtual) constructor called | |
PolyBase constructor called | |
PolyBase::virtual_foo called | |
Base1 constructor called | |
Derived1 constructor called | |
Base2 constructor called | |
Derived2 constructor called | |
TheMember constructor called: PolyBase | |
TheObject::virtual_foo called | |
TheMember constructor called: default | |
TheMember constructor called:2 | |
TheMember constructor called:3 | |
TheObject constructor called |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
这里可以看出,在基类构造函数中调用虚函数,无法调用到子类的实现,原因就在于子类vptr的初始化在基类构造函数之后, 一些纯虚函数的调用即出于此。