C++ 标准特性:委托构造与继承构造
C++ 标准特性:委托构造与继承构造
一、委托构造函数(Delegating Constructor)—— C++11
1.1 概述
委托构造函数允许当前类的某个构造函数调用同类的其他构造函数来完成初始化。这样可以避免在多个构造函数中编写重复的初始化代码。
1.2 委托构造函数与普通构造函数的区别
| 区别点 | 普通构造函数 | 委托构造函数 |
|---|---|---|
| 成员初始值列表 | 初始化成员变量 | 只有一个参数,即同类中另一个构造函数 |
| 函数体 | 有 | 有 |
| 执行顺序 | 初始化列表 → 函数体 | 被委托函数初始化列表 →被委托函数函数体→ 委托构造函数函数体 |
关键规则:当被委托构造函数的函数体中有代码时,先执行完被委托构造函数的函数体,然后才会执行委托构造函数的函数体。
1.3 执行流程图解
委托构造函数 Test(int d) │ ├→ 调用被委托构造函数 Test("default", d) │ ├→ 初始化列表:_data(d), _str("default") │ └→ 函数体:cout << "普通构造函数" │ └→ 委托构造函数自身的函数体:cout << "委托构造函数"1.4 示例代码
#include<iostream>usingnamespacestd;// 创建一个类classTestC{public:// 普通构造函数TestC(string s,intd):_data(d),_str(s){cout<<"程序执行:普通构造函数的函数体"<<endl;cout<<endl;}// 委托构造函数 ①:只传 int,string 用默认值TestC(intd):TestC("default",d){cout<<"程序执行:委托构造函数的函数体"<<endl;cout<<endl;}// 委托构造函数 ②:只传 string,int 用默认值TestC(string s):TestC(s,0){cout<<"程序执行:委托构造函数的函数体"<<endl;cout<<endl;}voidprintData(){cout<<"------程序执行:普通成员函数的函数体------"<<endl;cout<<"数据成员_data的值为:"<<_data<<endl;cout<<"数据成员_str的值为:"<<_str<<endl;cout<<endl;}private:int_data;string _str;};intmain(){TestCobjc1("hello",10);// 普通构造函数objc1.printData();TestCobjc2("helo",20);// 普通构造函数objc2.printData();TestCobjc3("hello");// 委托构造函数 → 内部调用 TestC("hello", 0)objc3.printData();return0;}1.5 调用分析
| 对象 | 构造方式 | 实际调用链 |
|---|---|---|
objc1("hello", 10) | 普通构造 | 直接匹配TestC(string, int) |
objc2("helo", 20) | 普通构造 | 直接匹配TestC(string, int) |
objc3("hello") | 委托构造 | TestC(string)→TestC("hello", 0) |
二、继承构造函数(Inheriting Constructor)—— C++11
2.1 概述
在 C++ 中,构造函数不能是虚函数,因此构造函数不能被继承。但从 C++11 开始,可以通过using关键字达到继承构造函数的效果——让派生类"借用"基类的构造函数。
2.2 原理
using Base::Base;—— 派生类自动获得基类的所有构造函数using Base::func;—— 派生类也可以引入基类的非虚成员函数
2.3 示例代码
#include<iostream>usingnamespacestd;structA{voidfunc(doubled){cout<<"基类A:"<<d<<endl<<endl;}};structB:A{// C++11 标准中,利用 using 关键字,使派生类可以继承父类的成员函数usingA::func;voidfunc(inti){cout<<"派生类:"<<i<<endl;}};intmain(){A a;a.func(78);// 调用 A::func(double)B b;b.func(87);// 调用 B::func(int),就近匹配return0;}2.4 调用分析
| 调用 | 匹配函数 | 原因 |
|---|---|---|
a.func(78) | A::func(double) | A只有一个func,78隐式转为double |
b.func(87) | B::func(int) | B有两份func,87精确匹配int版本 |
b.func(87.0) | A::func(double) | 精确匹配double版本(由using引入) |
using A::func;将基类的func(double)引入派生类的作用域,与派生类自己的func(int)构成重载关系。
2.5 using 继承构造函数(补充)
structBase{Base(intx){cout<<"Base(int)\n";}Base(intx,inty){cout<<"Base(int,int)\n";}};structDerived:Base{usingBase::Base;// 继承所有基类构造函数(C++11)};intmain(){Derivedd1(1);// 调用 Base(int)Derivedd2(1,2);// 调用 Base(int,int)return0;}三、对比总结
| 特性 | 委托构造 | 继承构造(using) |
|---|---|---|
| 关键词 | 在初始化列表调用同类构造函数 | using Base::Base; |
| 作用域 | 同一类内部 | 派生类与基类之间 |
| 解决什么问题 | 避免多构造函数重复初始化 | 让派生类可直接使用基类构造函数 |
| 执行顺序 | 先被委托函数体 → 再委托函数体 | 基类构造 → 派生类构造 |
| C++ 版本 | C++11 | C++11 |