C++11委托构造函数

1.简介

委托构造函数(Delegating Constructor)由C++11引入,是对C++构造函数的改进,允许构造函数通过初始化列表调用同一个类的其他构造函数,目的是简化构造函数的书写,提高代码的可维护性,避免代码冗余膨胀。

通俗来讲,一个委托构造函数使用它所属的类的其他构造函数执行自己的初始化过程,或者说它把自己的一些(或者全部)职责委托给了其他构造函数。和其他构造函数一样,一个委托构造函数也有一个成员初始化列表和一个函数体,成员初始化列表只能包含一个其它构造函数,不能再包含其它成员变量的初始化,且参数列表必须与构造函数匹配。

首先看一下一个不使用委托构造函数造成代码冗余的例子。

class Foo
{
public:
    Foo() :type(4), name('x') {initRest();}
    Foo(int i) : type(i), name('x') {initRest();}
    Foo(char c) :type(4), name(c) {initRest();}

private:
    void initRest() {/* init othre members */}
    int type;
    char name;
    //...
};

从上面的代码片段可以看出,类Foo的三个构造函数除了参数不同,初始化列表、函数体基本相同,其代码存在着很多重复。在C++11中,我们可以使用委托构造函数来减少代码重复,精简构造函数。

class Foo
{
public:
    Foo() {initRest(); }
    Foo(int i) : Foo() {type = i;}
    Foo(char e) : Foo() {name = e;}
private:
    void initRest() { /* init othre members */}
    int type{1};
    char name{'a'};
};

一个委托构造函数想要委托另一个构造函数,那么被委托的构造函数应该包含较大数量的参数,初始化较多的成员变量。而且在委托其他构造函数后,不能再进行成员列表初始化,而只能在函数体内对其他成员变量进行赋值。

2.注意事项

(1)不要形成委托坏。 在构造函数较多的时候,我们可能拥有多个委托构造函数,而一些目标构造函数很可能也是委托构造函数,这样依赖,我们就可能在委托构造函数中形成链状的委托构造关系,形成委托坏(Delegation Cycle)。

class Foo
{
public:
    Foo(int i) : Foo('c') { type = i; }
    Foo(char c) : Foo(1) { name = c; }
private:
    int type;
    char name;
};

其中Foo(int i)与Foo(char c)相互委托就形成了委托坏,这样会导致编译错误。

(2)如果在委托构造函数中使用try,可以捕获目标构造函数中抛出的异常。

#include <iostream> 
using namespace std;

class Foo
{
public:
    Foo(int i) try: Foo(i,'c') 
    {
        cout<<"start assignment"<<endl;
        type = i; 
    }
    catch(...)
    {
        cout<<"caugth exception"<<endl;
    }

private:
    Foo(int i,char c) 
    {
        cout<<"throw exception"<<endl;
        throw 0;
    }
    int type;
    char name;

};

int main()
{
    Foo f(1);
    return 0;
}

程序输出结果:

throw exception
caugth exception

可见在目表构造函数Foo(int i,char c)中抛出异常,在委托构造函数Foo(int i)中可以进行捕获,并且目标构造函数体内的代码并不会被执行。这样的设计是合理的,因为目标构造函数抛出异常说明对象并没有完成初始化,在委托构造函数中进行赋值操作都是一些无意义的动作。


[1]C++Primer [2]深入理解C++11 [3]关于使用C++11中委托构造函数

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏海天一树

小朋友学C语言(22):循环

C语言有三种循环方式,除了前面讲过的for循环外,还有while和do while两种形式。 (一)while循环 #include <stdio.h> in...

3479
来自专栏和蔼的张星的图像处理专栏

702. 连接两个字符串中的不同字符

连接两个字符串中的不同字符。 给出两个字符串, 你需要修改第一个字符串,将所有与第二个字符串中相同的字符删除, 并且第二个字符串中不同的字符与第一个字符串的不...

1371
来自专栏GreenLeaves

JavaScript之数组学习

在JavaScript中,数组用关键字Array来声明。声明数组的同时还可以指定数组初始元素的大小,也就是数组的长度;下面代码定义了一个数组长度为6的数组; v...

23010
来自专栏猿人谷

Java初学总结

1.对象的比较    “==”操作符用于比较两个对象的内存地址值是否相等    equals() 方法用于比较两个对象的内容是否一致  如下列: 1 publ...

22010
来自专栏Django Scrapy

python使用正则表达式

正则表达式 目标: 了解 : (0)\w 匹配 一个字母或者数字 (1)\d 只匹配数字 (2)\s 至少匹配一个空格 同理"\_","\-"分别匹配 ...

3948
来自专栏牛肉圆粉不加葱

(3) - Scala case class那些你不知道的知识

除了在模式匹配中使用之外,unapply 方法可以让你结构 case class 来提取它的字段,如:

901
来自专栏大闲人柴毛毛

稳扎稳打JS——this

this的值是在运行时确定的 JS中的this究竟代表什么,这是在程序运行时根据上下文环境确定,可以分为以下几种情况。 1. 全局作用域中的this 在全局作...

4145
来自专栏程序员互动联盟

【编程基础】C语言之指针二

指针和数组 C语言的数组表示一段连续的内存空间,用来存储多个特定类型的对象。与之相反,指针用来存储单个内存地址。数组和指针不是同一种结构因此不可以互相转换。而数...

3684
来自专栏wym

运算符重载(超详细)

C++中预定义的运算符的操作对象只能是基本数据类型。但实际上,对于许多用户自定义类型(例如类),也需要类似的运算操作。这时就必须在C++中重新定义这些运算符,赋...

1412
来自专栏技术专栏

Python3入门与实践(四): 面向对象

==当通过 student.name获取变量值的时候,首先会查找实例变量里有没有name属性,如果有则返回,如果没有就会去类变量里找,如果还是没有则会报错==

842

扫码关注云+社区

领取腾讯云代金券