标签:
class Word { private: String _name; int _cnt; public: // 没有错误,但是太naive Word() { _name = 0; _cnt = 0; } };在这里,Word构造函数会先产生一个临时性的String对象,然后将它初始化,再以一个赋值运算符将临时对象指定给_name,然后再销毁临时对象。以下是构造函数可能的内部扩张结果:
// C++伪代码 Word::Word( /* This pointer goes here */) { // 调用String的default constructor _name.String::String(); // 产生临时对象 String temp = String(0); // "memberwise"地拷贝_name _name.String::operator=(temp); // 销毁临时对象 temp.String::~String(); _cnt = 0; }对程序代码反复审查并修正,得到一个明显更有效率的实现方法:
// 较佳的方式 Word::Word : _name(0) { _cnt = 0; } 它会被扩张成这样子: // C++伪代码 Word::Word( /* This pointer goes here */ ) { // 调用String(int) constructor _name.String::String(0); _cnt = 0; }顺便一提,陷阱最可能发生在这种形式的template code中:
template <class type> foo<type>::foo(type t) { // 可能是也可能不是个好主意 // 视type的真正类型而定 _t = 0; }这会引导某些程序员十分积极进取地坚持所有的成员初始化操作必须在成员初始化列表中完成,甚至即使是一个行为良好的成员如_cnt:
// 坚持此种代码风格 Word::Word() : _cnt(0), _name(0) {}成员初始化列表中到底发生了什么事情?许多人对list的语法感到迷惑,误以为它是一组函数调用,当然不是!
// C++伪代码 Word::Word( /* this pointer goes here */ ) { _name.String::String(0); _cnt = 0; }它看起来很像是在构造函数中指定_cnt的值,事实上,有一些微妙的地方要注意:列表中的项目次序是由类中成员的声明次序决定的,而不是初始化列表中的排列顺序决定的。在本例的Word类中,_name被声明在_cnt之前,所以它的初始化比_cnt早。
class X { private: int i; int j; public: X (int val) : j(val), i(j) {} };上述程序代码看起来好像要把j设初值为val,然后把i设初值为j。但是由于声明顺序的原因,初始化列表中的i(j)比j(val)更早执行。而j开始并没有初始值,所以i(j)的执行结果导致i会被初始化为一个无法预测的值。
// 一个有趣的问题 X::x(int val) : j(val) { i = j; }j的初始化顺序会插入在显式用户赋值操作(i=j)之前还是之后呢?
// X::xfoo()被调用 X::X(int val) : i(xfoo(val)), j(val) {}其中xfoo()是X的一个成员函数,答案是yes.但是最好使用"存在于构造函数提内的一个成员",而不要使用"存在于成员初始化列表中的成员",来为另一个成员设定初始值.并不确定xfoo()对X object的依赖性有多高,如果把xfoo()放在构造函数体内,那么对于"到底哪一个member在xfoo()执行时被设置初始值"这件事,就可以给出确定的答案.
// constructor扩张后的结果 X::X( /* this pointer, */ int val) { i = this->xfoo(val); j = val; }如果一个派生类成员函数被调用,其返回值被当作基类构造函数的一个参数,将会如何?
// 调用FooBar::fval()可以吗? class FooBar : public X { private: int _fval; public: int fval() { return _fval; } // derived class member function FooBar(int val) : _fval(val), X(fval()) // fval()作为base class constructor的参数 {} };下面是它可能的扩张结果:
// C++伪代码 FooBar::FooBar( /* this pointer goes here */ ) { X::X(this, this->fval()); _fval = val; }它的确不是一个好主意.
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/yiranant/article/details/47192269