1.初始化是“给与对象初值”的过程。对于用户自定义类型的对象,初始化由构造函数执行。所谓的默认构造函数,要不是没有参数,要不就是每个参数都有缺省值,考虑以下例子:
class A{
public:
A();
};
class B{
public:
explicit B(int x = 0, bool b = true);
};
class C{
public:
explicit C(int x);
};
其中,A和B均为default构造函数,C不是default构造函数。
2.explicit可以用来防止隐式类型转换,但仍可被用来显示类型转换,被声明为explicit的构造函数更受欢迎,因为其可以禁止编译器执行非预期的类型转换,那将是你不愿看到的,除非你有一个好理由允许构造函数被用于隐式类型转换,否则将它声明为explicit吧。
考虑以下函数:
void doSomething(B bObject);
传递一个B对象给deSomething函数再正常不过
B bObj1;
doSomething(bObj1);
有时B对象需要传入参数构造,于是
B bObj2(7);
doSomething(bObj2); //构造函数的bool值缺省为true
如果在程序中出现这种情况
doSomething(7);
那么编译器将会识别出这个错误,因为int到B之间禁止隐式转换,这就是explicit发挥作用的时候。
于是,我们希望代码写成这样
doSomething(B(7));
使用B的构造函数显式将int转换成B对象。
3.copy构造函数被用来“以同类型对象初始化自我对象”,copy赋值操作符被用来“从另一个同型对象中拷贝其值到自我对象”。
class Widget{
public:
Widget(); //默认构造函数
Widget(const Widget& rhs); //copy构造函数
Widget& operator=(const Widget& rhs); //copy赋值操作符
...
};
Widget w1; //调用默认构造函数
Widget w2(w1); //调用copy构造函数
w1 = w2; //调用copy赋值操作符
特别要注意,Widget w3 = w2;也是调用copy构造函数,如果一个对象被定义,那么就一定会调用到构造函数,不可能调用copy赋值操作符,如果没有对象被定义,如前面的w1 = w2,那么就不会有构造函数被调用,那么当然就是赋值操作符被调用。
再考虑以下例子:
bool hasAccept(Widget w);
...
Widget aWidget;
if(hasAccept(aWidget))...
其中w对象也是由copy构造函数复制aWidget完成的,其是以Pass-by-value的方式传递给hasAccept函数的,这通常是个坏主意,Pass-by-reference-to-const往往是较好的选择。