Effective C++ 条款04:确定对象被使用前已先被初始化

C++对于自动初始化变量没有一个明确的规定,跟编译器有关。因此,我们应该永远在使用对象之前先将它初始化。

int x = 0;
const char* text = "A C-style string";
// input
double d;
std::cin >> d;

赋值与初始化

我们设计两个类PhoneNumber和ABEntry。PhoneNumber表示电话,ABEntry表示通讯录,用于保存PhoneNumber。

class PhoneNumber{}

class ABEntry{
public:
    ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones);
private:
    std::string theName;
    std::string theAddress;
    std::list<PhoneNumber> thePhones;
    int numTimesConsulted;
}

当然,这两个类写的过于复杂了。我们只需要关注ABEntry的构造函数就行了。这个构造函数有3个参数,name,address和phones。我们需要用这三个参数构造这类自己的成员变量。

ABEntry::ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones) {
    theName = name;
    theAddress = address;
    thePhones = phones;
    numTimesConsulted = 0;
}

如果是这样写的,就是赋值而不是初始化。赋值的步骤是先调用默认构造函数,然后再调用这个构造函数给成员变量赋值。

赋值会导致一个问题,就是在默认构造的时候编译器会给成员变量整一个默认值(或者随机值)。

初始化是下面这样写的

ABEntry::ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones)
    :theName(name),
	 theAddress(address),
	 thePhones(phones),
	 numTimesConsulted(0)
{}

初始化直接调用这个构造函数初始化成员变量。这样赋值会调用两次构造函数,而初始化只用调用一次。效率更高一点。

初始化与赋值还有个区别是在初始化成员变量时用的拷贝构造函数,而赋值用的是赋值运算符。

const和引用的成员变量一定需要有初值。所以不能采用赋值的方法,只能通过初始化的形式。

所以类的所有的成员变量都用这种成员列表的方法初始化就行了。虽然有时候成员变量很多的时候看起来会很丑。

初始化次序

类成员的初始化次序是在类定义的时候决定的,比如ABEntry里。theName是第一个,theAddress是第二个,以此类推。

所以我们在用初始化成员列表初始化的时候,最好也按照这个顺序。否则可能会出现一些意想不到的问题。比如我们初始化了一个a,然后想用a去初始化b。但在类的定义中,b比a先定义。

class Test{
public:
    Test(int _a)
        :a(_a), b(a){} 
private:
    int b;
    int a;
}

我们希望_a先初始化a,然后a再初始化b。但实际上是先a初始化b,然后才是_a初始化a。这就会导致问题。

后面编译的东西以后再说吧...

posted @ 2021-06-22 10:32  Destiny233  阅读(55)  评论(0)    收藏  举报