C++11的委派构造函数

news/2024/7/4 0:53:00 标签: class, c++
class="baidu_pl">
class="article_content clearfix">
class="markdown_views prism-atom-one-dark">

一.目的

委派构造函数是C++ 11中对C++的构造函数的一项改进,其目的 也是为了减少程序员书写构造函数的时间。通过委派其他构造函数, 多构造函数的类编写将更加容易。

二.委派构造函数的前因后果

class Info 
{
public:
    Info() : type(1), name('a'){initRest();}
    Info(int i) : type(i), name('a'){initRest();}
    Info(char e) : type(1), name(e){initRest()}
    ~Info(){}
private:
    void initRest(){}
    int type;
    char name;
};

在类Info中,一共存在三个构造函数,并且三个构造函数中都调用了initRest()函数,这样的代码存在很大的冗余性。

下面是使用C++11的快速初始化成员变量的新特性来改写上面这段代码:

class Info()
{
public:
    Info(){initRest();}
    Info(int i) : type(i)(initRest();)
    Info(char e) : name (e){initRest();}
private:
    initRest();
    int type {1};
    char name {'e'};
};

上面的代码虽然经过C++ 11的快速初始化成员变量的方式改造了,但是仍然存在一个问题,就是每个构造函数都调用了initRest函数,代码的冗余度还是很大。

下面这一版是一种存在错误的改进方式

class Info
{
public:
    Info(){initRest();}
    Info(int i){this->Info(); this->type = i;}
    Info(char e){this->Info(); this->name = e;}
    ~Info(){}
private:
    int type;
    char name;
    initRest(){}
};

上面的代码编译器是编译不过的,即使这段代码能编译过,它也不是最优的。当然,我们还可以开发出一个更具有“ 黑客 精神” 的版本:

class Info
{
public:
    Info(){};
    Info(int i){new (this) Info(); type = i;}
    Info(char e){new (this) Info(); name = e;}
    ~Info(){}
private:
    initRest(){}
    int type;
    char e;
};

这里我们使用了placement new来强制在本对象地址( this指针所指 地址)上调用类的构造函数。这样一来,我们可以绕过编译器的检查,这种方法很危险,不推荐使用。

以下是委派构造函数实现的例子

class Info
{
public:
    Info(){initRest();}
    Info(int i) : Info() {this->type  = i;}
    Info(char e) : Info(){this->name = e;}
    ~Info(){}
private:
    void initRest(){}
    int type {1};
    char name {‘a’};
};

在 Info( int) 和 Info( char) 的初始化列表的位置, 调用 了“ 基准版本” 的 构造函数 Info()。为了区分被调用者和调用者,称在初始化列表中调用“基准版本” 的构造函数为委派构造函数( delegating constructor),而被调用的“ 基准版本” 则为目标构造函数( target constructor)。 在 C++ 11 中, 所谓委派构造, 就是指委派函数将构造的任务委派给了目标构造函数来完成这样一种类构造的方式。在上面代码中, 委派构造函数只能在函数体中为 type、 name 等成员赋 初值。 这是由于委派构造函数不能有初始化列表造成的。 在 C++ 中, 构造函数不能 同时“ 委派” 和使用初始化列表, 所以如果委派 构造函数要给变量赋初始值,初始化代码必须放在函数体中。

struct Rule
{
    int i;
    Rule(int a) : i(1){}
    Rule() : Rule(10), i(1){} //无法通过编译
}

上面的代码由于不能在初始化列表中既初始化成员, 又委托其他构造 函数完成构造。故而它是无法通过编译的。

以下代码是通过私有化构造函数来进行代码改进:

class Info 
{ 
public: 
    Info() : Info( 1, 'a') { } 
    Info( int i) : Info( i, 'a') { } 
    Info( char e): Info( 1, e) { } 
private: 
    Info(int i, char e): type(i), name(e) {} 
    int type; 
    char name; 
};

在上面代码中, 我们定义了一个私有的目标构造函数Info( int, char),这个构造函数接受两个参数,并将参数在初始化列表中初始化。 而且由于这个目标构造函数的存在,我们可以不再需要 InitRest 函数了,而是将其代码都放入 Info( int, char) 中。 这样一来, 其他 委派构造函数就可以委托该目标构造函数来完成构造。

三.多个委派构造函数

class Info 
{ 
public: 
    Info() : Info( 1) { } //委派构造函数 
    Info( int i) : Info( i, 'a') { } //既是目标构造函数,也是委派构造函数 
    Info( char e): Info( 1, e) { }
private: 
    Info( int i, char e): type( i), name( e) { } // 目标构造函数
    int type; 
    char name; 
};

以上代码就是这样一种链状委托构造,这里我们使 Info() 委托Info( int) 进行构造,而Info( int) 又委托 Info( int, char) 进行构造。在委托 构造的链状关系中, 有一点程序员必须注意, 就是不能形成委托环( delegation cycle)。

例:

    struct Rule2
     {  
         int i, c;  
         Rule2(): Rule2( 2) {}  
         Rule2( int i): Rule2(' c') {}  
         Rule2( char c): Rule2( 2) {}  
     };

Rule2 定义中, Rule2()、 Rule2( int) 和Rule2( char) 都依赖于别的 构造函数,形成环委托构造关系。 这样的代码通常会导致编译错误。

#include < list>  
#include < vector>  
#include < deque>  
using namespace std; 
class TDConstructed 
{ 
     template< class T> TDConstructed( T first, T last) : l( first, last) {} list< int> l; 
public: 
    TDConstructed( vector< short> & v):

    TDConstructed( v. begin(), v. end()) {} 
    TDConstructed( deque< int> & d): TDConstructed( d. begin(), d. end()) {} 
}; 

在以上代码中, 我们定义了一个构造函数模板。 而通过两个委派构造 函数的委托, 构造函数模板会被实例化。 T会分别被推导为 vector< short>:: iterator 和 deque< int>:: iterator 两种类型。 这样一来,我们的TDConstructed 类就可以很容易地接受多种容器对其进行初始化。 这无疑比罗列不同类型的构造函数方便了很多。 可以说,委托 构造使得构造函数的泛型编程也成为了一种可能。

四.委托构造的异常处理

函数中使用try的话,那么从目标构造函数中产生的异常,都可以在委派构造函数中被捕捉到。

#include < iostream> 
 using namespace std; 
 class DCExcept  
 {  
 public:  
     DCExcept( double d) 
     try : DCExcept( 1, d) 
     {  
        cout << "Run the body." << endl; 
     }  
     catch(...)  
     {  
         cout << "caught exception." << endl; 
     } 
     private: 
         DCExcept( int i, double d)
         {  
             cout << "going to throw!" << TDConstructed( v. begin(), v. end()) 
            {
            }
        TDConstructed( deque< int> & d):TDConstructed( d. begin(), d. end()) {} 
};

http://www.niftyadmin.cn/n/744392.html

相关文章

2021年建筑焊工(建筑特殊工种)考试题库及建筑焊工(建筑特殊工种)考试资料

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 建筑焊工(建筑特殊工种)考试题库考前必练&#xff01;安全生产模拟考试一点通每个月更新建筑焊工(建筑特殊工种)考试资料题目及答案&#xff01;多做几遍&#xff0c;其实通过建筑焊工(建筑特殊工种)证考试很简单。 1…

B. K-th Beautiful String(字符串+字典序)Codeforces Round #629 (Div. 3)

原理链接&#xff1a; https://codeforces.com/problemset/problem/1328/B 测试样例&#xff1a; Input 7 5 1 5 2 5 8 5 10 3 1 3 2 20 100 Output aaabb aabab baaba bbaaa abb bab aaaaabaaaaabaaaaaaaa 题意&#xff1a; 给你一个长为nnn的只由(n−2)(n-2)(n−2)个aaa和22…

2021年聚合工艺多少分及格及聚合工艺考试总结

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 聚合工艺多少分及格是安全生产模拟考试一点通总题库中随机出的一套聚合工艺考试总结&#xff0c;在公众号安全生产模拟考试一点通上点击聚合工艺作业手机同步练习。2021年聚合工艺多少分及格及聚合工艺考试总结 1、【…

2021年氟化工艺考试题库及氟化工艺复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 氟化工艺考试题库参考答案及氟化工艺考试试题解析由安全生产模拟考试一点通题库老师及氟化工艺操作证已考过的学员汇总&#xff0c;相对有效帮助氟化工艺复审考试学员顺利通过考试。 1、【判断题】消防安全重点单位除…

C++ 11的继承构造函数

一.概述 C是面向对象的基石&#xff0c;类具有可派生性。派生类可以自动获得基类的成员变量和接口&#xff0c;不过基类的非虚函数则无法再被派生类使用了。如果派生类要使用基类的构造函数&#xff0c;通常需要在构造函数中显示声明。 例如&#xff1a; struct A {A(int i)…

C. Ternary XOR(进制问题+思维)Codeforces Round #629 (Div. 3)

原理链接&#xff1a; https://codeforces.com/contest/1328/problem/C 测试样例&#xff1a; Input 4 5 22222 5 21211 1 2 9 220222021 Output 11111 11111 11000 10211 1 1 110111011 110111010 题意&#xff1a; 给定一个长度为3的三进制数为xxx&#xff0c;其中xxx是由xa⨀…

2021年焊工(技师)考试技巧及焊工(技师)模拟考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 焊工&#xff08;技师&#xff09;考试技巧参考答案及焊工&#xff08;技师&#xff09;考试试题解析由安全生产模拟考试一点通题库老师及焊工&#xff08;技师&#xff09;操作证已考过的学员汇总&#xff0c;相对有…

QT中在QFrame中动态产生控件

void MainWindow::start() {for(int i0; i < 1000; i){QFrame *f new QFrame();QLineEdit *anew QLineEdit(f);ui->verticalLayout_7->addWidget(f);b->setText(QString::number(i));a->setText(QString::number(i));} }关注问我技术公众号&#xff0c;加小问&…