[C++]对象初始化 / 构造函数
最好不要将对象设为static duration的(静态的、全局的),这样的话,对象的初始化顺序以及销毁顺序均不可控,多线程时可能出现问题。
构造函数:
构造函数可能会调用内部函数,如果这个函数是虚函数,可能出现问题(其实也不是啥问题,如果熟悉派生类的构造过程的话)。详见下例:
#include <iostream> using std::cout; using std::endl; class Base { public: virtual void Foo(){ cout << "执行了Base的Foo()函数" << endl; } Base() { cout << "执行了Base的构造函数并开始调用Foo()" << endl; Foo(); } void Func() { cout << "执行了Base的Func()函数并开始调用Foo()" << endl; Foo(); } }; class Derive : public Base { public: virtual void Foo(){ cout << "执行了Derive中的Foo()函数" << endl; } }; void main() { cout << "创建Derive的实例。构造时执行Base的Foo()函数" << endl; Derive obj; cout << endl; cout << "Derive实例创建后,基类的Func()执行Derive的Foo()函数" << endl; obj.Func(); cout << endl; cout << "改变其类型为Base后,基类的Func()执行Base的Foo()函数←这是virtual的特性" << endl; Base obj_base = (Base)obj; obj_base.Func(); cout << endl << "改变指针的类型不会改变Foo()的选择,必须强制类型转换" << endl; cout << "原因是强制类型转换生成了新的对象起始地址" << endl; cout << "Derive对象的地址:"<< &obj << " ~ " << &obj + sizeof(Derive) << endl; cout << "Base 对象的地址:"<< &obj_base << " ~ " << &obj_base + sizeof(Base) << endl; system("pause"); }
结果:
创建Derive的实例。构造时执行Base的Foo()函数
执行了Base的构造函数并开始调用Foo()
执行了Base的Foo()函数
Derive实例创建后,基类的Func()执行Derive的Foo()函数
执行了Base的Func()函数并开始调用Foo()
执行了Derive中的Foo()函数
改变其类型为Base后,基类的Func()执行Base的Foo()函数←这是virtual的特性
执行了Base的Func()函数并开始调用Foo()
执行了Base的Foo()函数
改变指针的类型不会改变Foo()的选择,必须强制类型转换
原因是强制类型转换生成了新的对象起始地址
Derive对象的地址:003CFA10 ~ 003CFA20
Base 对象的地址:003CFA04 ~ 003CFA14
请按任意键继续. . .
创建对象的数组时会执行默认构造函数。
默认构造函数
默认构造函数执行那些无逻辑意义的初始化(比如int置为0,枚举置为NULL等等),对于有逻辑意义的初始化,放在Init()函数中进行。
对于Interface,尽量不指定构造函数。如果要定义构造函数,也只定义默认构造函数。并且,将默认构造函数置为protected。这样既防止了创建Interface的实例,又可以在实现接口时调用构造函数。
public:实例课访问,成员函数可访问。public派生类实例可访问,成员函数可访问。
protected:实例不可访问,成员函数可访问。public派生类实例不可访问,成员函数可访问。
private:实例不可访问,成员函数可访问。public派生类实例不可访问,成员函数不可访问。
只有一个参数的构造函数:
只有一个参数的构造函数会被认为是implicit,即隐式转换函数。它除了构造函数的功能外,还具有隐式转换的功能。
这样子的特性不太好,所以最好显式声明为explicit,禁用隐式转换。
比起其他的单参数构造函数,拷贝构造函数更加应该引起重视:因为它会被默认隐式创建。最好也禁用之——使用private定义。
同时记得禁用赋值——将operator=(Type)也置为private。