[C++]对象初始化 / 构造函数

最好不要将对象设为static duration的(静态的、全局的),这样的话,对象的初始化顺序以及销毁顺序均不可控,多线程时可能出现问题。

构造函数:

构造函数可能会调用内部函数,如果这个函数是虚函数,可能出现问题(其实也不是啥问题,如果熟悉派生类的构造过程的话)。详见下例:

构造函数不会重载virtual
#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。

posted @ 2012-04-09 20:48  斯啦丝拉  阅读(429)  评论(0编辑  收藏  举报