3.5、委托构造函数(委托同类构造函数)

委托构造函数是什么?

传统C++中,一个类如果有多个构造函数(重载),它们往往会有很多重复的初始化代码。比如:

class Foo {
public:
    Foo() {
        // 初始化成员A、B、C
    }
    Foo(int x) {
        // 初始化成员A、B、C
        // 额外处理x
    }
    Foo(int x, int y) {
        // 初始化成员A、B、C
        // 额外处理x和y
    }
};

你会发现,初始化成员A、B、C的代码在每个构造函数里都写了一遍,代码冗余,维护起来麻烦。

委托构造函数就是让一个构造函数“委托”调用同类中另一个构造函数,复用它的初始化逻辑。换句话说,就是“我不自己写初始化了,交给你那个构造函数去做”,这样只写一份初始化代码,其他构造函数都调用它。

传统写法 vs 委托构造函数写法对比

传统写法(代码冗余)

#include <iostream>
using namespace std;

class Person {
    string name;
    int age;
public:
    Person() {
        name = "Unknown";
        age = 0;
        cout << "Default constructor\n";
    }
    Person(string n) {
        name = n;
        age = 0;
        cout << "One-arg constructor\n";
    }
    Person(string n, int a) {
        name = n;
        age = a;
        cout << "Two-arg constructor\n";
    }
    void print() {
        cout << name << ", " << age << endl;
    }
};

int main() {
    Person p1;
    Person p2("Alice");
    Person p3("Bob"30);

    p1.print();
    p2.print();
    p3.print();
    return 0;
}

这里每个构造函数都重复写了name和age的初始化,代码臃肿。

委托构造函数写法(代码简洁)

#include <iostream>
using namespace std;

class Person {
    string name;
    int age;
public:
    Person() : Person("Unknown"0) {
        cout << "Default constructor delegates\n";
    }
    Person(string n) : Person(n, 0) {
        cout << "One-arg constructor delegates\n";
    }
    Person(string n, int a) : name(n), age(a) {
        cout << "Two-arg constructor\n";
    }
    void print() {
        cout << name << ", " << age << endl;
    }
};

int main() {
    Person p1;
    Person p2("Alice");
    Person p3("Bob"30);

    p1.print();
    p2.print();
    p3.print();
    return 0;
}

这里,默认构造函数委托给了带两个参数的构造函数,带一个参数的构造函数也委托给了带两个参数的构造函数,初始化逻辑只写了一遍,代码清爽且易维护。

委托构造函数的设计哲学

  • • 减少代码重复:初始化代码只写一遍,避免多个构造函数重复书写相同代码。
  • • 提高代码可维护性:修改初始化逻辑只需改一个构造函数,降低错误风险。
  • • 逻辑清晰:构造函数之间职责分明,层层委托,符合“先通用后特殊”的设计原则。
  • • 避免初始化冲突:委托构造函数只能调用一个其他构造函数,且不能同时初始化成员变量,避免初始化顺序混乱。

最佳使用场景

  • • 类中有多个构造函数,且它们之间有大量重复初始化代码。
  • • 需要统一初始化逻辑,减少维护成本。
  • • 构造函数参数较多,部分构造函数参数是另一些构造函数参数的子集。
  • • 需要构造函数之间分层调用,逐步完善对象状态。

优缺点分析

优点 缺点
减少构造函数间代码重复,提升维护性 委托构造函数只能调用一个其他构造函数,限制灵活性
逻辑清晰,构造职责分明 不能和成员初始化列表同时使用,限制了初始化方式
避免初始化代码不一致导致的bug 多层委托可能导致“委托环”错误,编译器会报错
支持异常传播,委托构造函数中可捕获目标构造函数异常 委托构造函数中不能再初始化成员变量,只能在函数体内赋值

常见误用及后果

  • • 形成委托环(Delegation Cycle)
    比如构造函数A委托构造函数B,构造函数B又委托构造函数A,会导致编译错误。
  • • 委托构造函数中同时初始化成员变量
    委托构造函数初始化列表只能包含一个其他构造函数调用,不能再初始化成员变量,否则编译错误。
  • • 忽视异常传播
    如果目标构造函数抛出异常,委托构造函数可以捕获,但目标构造函数体内代码不会执行,委托函数中对成员赋值也可能无效。
  • • 滥用委托导致代码复杂
    多层委托链条过长,反而降低代码可读性和调试难度。

进阶示例:异常处理中的委托构造函数

#include <iostream>
using namespace std;

class Foo {
    int type;
    char name;
public:
    Foo(int i) try : Foo(i, 'c') {
        cout << "Start assignment\n";
        type = i;
    } catch (...) {
        cout << "Caught exception\n";
    }
private:
    Foo(int i, char c) {
        cout << "Throw exception\n";
        throw 0;
    }
};

int main() {
    try {
        Foo f(1);
    } catch (...) {
        cout << "Exception propagated to main\n";
    }
    return 0;
}

输出:

Throw exception
Caught exception
Exception propagated to main

说明委托构造函数可以捕获目标构造函数抛出的异常,且目标构造函数体内代码未执行,符合初始化语义。

委托构造函数的价值

委托构造函数是C++11对构造函数设计的精细打磨,它让构造函数之间的关系更清晰,代码更简洁,维护更轻松。它体现了现代C++追求**“代码复用与简洁表达”**的设计哲学,避免了传统构造函数中反复初始化的冗余和潜在错误。

我认为,委托构造函数的真正价值不仅是减少代码量,更是推动程序员以更结构化和模块化的思维来设计类的初始化流程。合理使用委托构造函数,配合现代C++的其他特性,能让你的代码既优雅又健壮。
本文首发于【讳疾忌医-note】公众号,未经授权,不得转载。
(加入我的知识星球,免费获取账号,解锁所有文章。)

阅读剩余
THE END