C++11标准中引入了两种构造函数的活用方法,可以适当地减轻一些情景下的码字负担。
1.继承构造函数
以往情况下,在派生类中调用基类的构造函数,一般需要在派生类中显式调用:
struct A { A(int i) {} }; struct B { B(int i) : A(i) {} };
当构造函数的花式(签名)很多的时候,继承类写起来就比较辛苦了。
在C++11标准中,可以通过using声明来简化这种操作(using声明在以前的标准中已经可以用在非构造函数里)
struct A { A(int i) {} A(double d, int i) {} A(float f, double d, int i) {} //... }; struct B { using A::A; //继承构造函数 //... };
需要注意的是,采用这种using声明有两个规矩:
- 如果基类的构造函数是private或是派生类是从基类中虚继承的,不能用这种方法;
- 一旦用了继承构造函数,编译器就不会为派生类生成默认构造函数(Visual Studio报error C2280),除非基类自己没有定义任何构造函数而触发了默认构造函数生成;
2.委派构造函数
委派构造函数常用在减少初始化过程的代码冗余问题,比如下面这个经典例子(我就这么干过):
class Info { public: Info() { InitRest(); } Info(int i) : type(i) { InitRest(); } Info(char c) : name(c) { InitRest();} private: void InitRest () { // 初始化其他东西 } int type {1}; char name {'a'}; //... };
使用一般方法,我们无法在自己构造函数里又调用自己的构造函数(突然想起了python的import this,哈哈),纵使函数签名不同也会报编译错误。
C++11中,可以这么写:
class Info { public: Info() { InitRest(); } Info(int i) : Info() { type = i; } Info(char c) : Info() { name = c; } private: void InitRest () { // 初始化其他东西 } int type {1}; char name {'a'}; //... };
但是要注意,委派构造函数不能和初始化列表并用,不然依旧编译错误。
比如我们不能搞Info(int i) : Info(), type(i) { } 。
不过有解决办法,比如可以声明一个私有的构造函数,它包括“完整”的参数输入,然后公有的其他构造函数调用它:
class Info { public: Info() : Info(1, 'a') { } // 或采用链状委派: Info(1) 或 Info('a') Info(int i) : Info(i, 'a') { } Info(char c) : Info(1, c) { } private: Info(int i, char e) : type(i), name(c) { } int type {1}; char name {'a'}; //... };
关于函数执行顺序,目标函数执行总是先于委派构造函数的。
参考文献
《深入理解C++11 (C++11新特性解析与应用)》