学习内容
本节学习委托构造函数在各版本的异同,后续请关注 学习C++11/14/17/20/23关键词版本更替 ,将持续更新~~
委托构造函数是在类的构造初始化列表中,不直接初始化类的成员变量,而是调用同一个类的其他构造函数,由被调用的构造函数完成成员初始化,当前构造函数仅需补充额外的初始化逻辑,或无额外逻辑
委托构造函数是C++11新引入特性,解决了传统C++构造函数之间代码冗余、初始化逻辑重复编写问题,允许同一个类的一个构造函数调用该类的另一个构造函数,实现初始化逻辑的复用
cpp
//C++11前
class Test
{
public:
Test(): string("") , used(false),num(0) , id(0){}
Test(string n) :string(n) , used(false),num(0) , id(0){}
Test(string n , bool u) :string(n) , used(u),num(0) , id(0){}
//....此处省略其余构造函数,皆为重复代码
private:
int id;
int num;
bool used;
string name;
};
委托构造函数核心价值:将公共初始化逻辑抽离到一个核心构造函数中,其他构造函数通过委托复用该逻辑
语法规则
委托构造函数语法集中在构造函数的初始化列表
cpp
class Test
{
public:
Test(): Test("Alice"){}
Test(string n) :Test( n , false) {}
Test(string n , bool u) :Test(n , u , 0 , 0 ){ }
private:
int id;
int num;
bool used;
string name;
};
定义对象时,根据构造函数的参数来匹配对应的构造函数,禁止循环委托(同一类中构造函数相互调用)
cpp
Test test();
Test test1 ("Bob");
委托函数写在初始化列表中,不能同时初始化成员变量和委托构造函数
cpp
//禁止以下写法 ,不能同时写
Test(string n , bool u ) : id(0) , num(0) , Test ( n,u ){}
支持多层委托,但是层数越多导致逻辑过长,可读性降低
委托构造函数必须是本类的,不能委托父类构造函数
被委托构造函数执行优先级更高
cpp
class Person
{
public:
Person ( string name_ , int age_) : name(name_) , age(age_){ cout<< "优先级最高,核心函数" <<endl; }
Person (string name_) : Person(name_ ,12) { cout << "优先级排名第二" << endl; }
Person() : Person("Invalid") { cout << " 优先级第三 " << endl; };
private:
string name;
int age;
}
Person p; //调用无参构造函数
注意
成员变量已由委托构造函数初始化完成,若在委托函数体中再次赋值,则会覆盖原有值,导致初始化逻辑混乱
cpp
class Test
{
public:
A(int a ): age( a ){}
A() : A(10){ age = 12; } //原值被覆盖为12,将逻辑写到核心构造里面可解决
private:
int age;
}
避免循环委托,编译期会检测,确定委托构造函数的终点是非委托核心构造函数
在继承体系中,委托构造不影响父类构造,子类的委托构造函数仅辅助子类内部的构造委托,父类的构造函数仍需在子类构造函数的初始化列表中显式调用,二者互不干扰
cpp
class Base
{
public:
Base(int a ) : age(a){}
private:
int age;
}
class Derived : puhlic Base
{
public:
Derived(int a, int d) : Base(b),data(d){}
Derived(int d) : Derived(10,d){}
private:
int data;
}
C++11,核心特性引入
初次引入委托构造函数,并完整定义该特性所有核心规则,包括:
- 初始化列表中委托同一个类构造函数语法
- 委托为初始化列表唯一项、禁止同时初始化成员变量约束
- 禁止循环委托、支持多层委托
- 被委托构造函数优先于委托构造函数体执行
- 仅适用于类内部构造函数委托、不影响父类构造调用边界
C++14无优化,无修改,无变更
C++17 兼容性增强,适配类内静态断言与内联变量
新增类内静态断言(static_assert)和内联变量(inline)特性,可与委托构造函数无缝配合,提升代码健壮性
类内static_assert: 可在类中直接添加静态断言,校验委托构造参数合法性
类内内联变量: 类的静态成员可直接在类内初始化;委托构造函数可直接使用初始化完成的静态变量
cpp
class Test
{
public:
Test(int a) : age(a)
{
static_assert( is_integral_v<int> , "参数必须为正整数");
}
Test() : Test( staValue){}
private:
int age;
inline static staValue = 12; //内联静态成员变量直接初始化
}
C++20 编译期支持constexpr委托构造
允许将委托构造函数标记为constexpr,支持编译期完成对象的委托初始化,其中:
被委托的构造函数也必须是constexpr
原有委托语法、执行顺序、约束规则不变
编译期初始化的对象,其成员变量为编译期常量,可用于模板参数、static_assert等
cpp
class Person
{
public:
constexpr Person ( string name_ , int age_) : name(name_) , age(age_){ cout<< "优先级最高,核心函数" <<endl; }
constexpr Person (string name_) : Person(name_ ,12) { cout << "优先级排名第二" << endl; }
constexpr Person() : Person("Invalid") { cout << " 优先级第三 " << endl; };
private:
string name;
int age;
}
constexpr Person p;
constexpr Person p1("Ana");
Concepts编译期参数约束,与委托构造函数配合,为构造函数添加编译期强类型约束,替代传统static_assert
cpp
template< class T>
concept NonNegativeInt = integral<T> && !signed<T>;
class Test
{
public:
Test(NonNegativeInt auto a) : age(9){}
Test() : Test( staValue){}
private:
int age;
}
Test t(-2); //error , -1不符合强类型约束
C++23 细节完成
适配显式对象构造(std::construct_at):使用std::construct_at在指定内存地址构造对象时,支持调用委托构造函数