尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

C++ 委托构造详解

C++ 委托构造详解 C 委托构造详解1、 什么是委托构造2、基本语法3、委托构造的规则与限制4、委托构造的典型应用场景4.1、 提供默认参数4.2 、处理 const 和引用成员4.3、 参数校验与归一化5、 委托构造与继承构造的区别6、 委托构造的注意事项7、总结二、代码示例1、 什么是委托构造委托构造Delegating Constructor是 C11 引入的一项特性允许一个构造函数在初始化列表中调用同一个类的另一个构造函数从而复用初始化逻辑避免代码重复。在 C11 之前如果同一个类有多个构造函数它们往往包含大量重复的初始化代码。常见的做法是抽出一个私有的init()成员函数来复用逻辑但这种方式存在缺陷成员变量无法在init()中通过初始化列表完成初始化只能先赋默认值再赋值对于const成员、引用成员以及没有默认构造函数的成员对象这种方式无法正常工作。委托构造从根本上解决了这个问题它让构造函数之间可以直接复用初始化列表所有成员初始化都在初始化列表中完成。2、基本语法委托构造的语法非常简洁只需在初始化列表中调用另一个构造函数即可classRectangle{public:// 目标构造函数被委托的构造函数Rectangle(intw,inth):width_(w),height_(h){}// 委托构造函数Rectangle():Rectangle(1,1){}private:intwidth_;intheight_;};在上面的例子中无参构造函数通过Rectangle(1, 1)委托给了带参构造函数将默认宽高都初始化为 1。3、委托构造的规则与限制使用委托构造时需要遵守以下规则委托调用必须写在初始化列表中且是初始化列表中唯一的成员初始化项。不能在一个构造函数中既委托其他构造函数又初始化成员变量。委托关系不能形成循环否则会导致编译错误。目标构造函数执行完毕后委托构造函数的函数体才会执行。如果目标构造函数抛出异常委托构造函数不会继续执行函数体。下面是一个非法示例classBadExample{public:BadExample(intx):BadExample(x,0),value_(x){}// 错误不能同时委托和初始化成员BadExample(intx,inty):x_(x),y_(y){}private:intx_;inty_;intvalue_;};4、委托构造的典型应用场景4.1、 提供默认参数当构造函数参数较多时可以通过委托构造提供不同层级的默认参数组合classHttpRequest{public:HttpRequest():HttpRequest(GET,/,HTTP/1.1){}HttpRequest(conststd::stringmethod,conststd::stringpath):HttpRequest(method,path,HTTP/1.1){}HttpRequest(conststd::stringmethod,conststd::stringpath,conststd::stringversion):method_(method),path_(path),version_(version){}private:std::string method_;std::string path_;std::string version_;};4.2 、处理 const 和引用成员对于包含const成员或引用成员的类无法通过init()函数完成初始化委托构造是理想的解决方案classConfig{public:Config():Config(1024,default){}Config(intsize,conststd::stringname):max_size_(size),name_(name){}private:constintmax_size_;// const 成员必须在初始化列表中初始化conststd::stringname_;// 引用成员同样如此};4.3、 参数校验与归一化可以在目标构造函数中完成参数校验委托构造函数只需传入合理的默认值classTemperature{public:Temperature():Temperature(25.0){}explicitTemperature(doublecelsius):celsius_(celsius){if(celsius_-273.15){throwstd::invalid_argument(温度不能低于绝对零度);}}private:doublecelsius_;};5、 委托构造与继承构造的区别委托构造和继承构造Inheriting Constructor是两个容易混淆的概念委托构造同一个类内部的构造函数之间互相调用复用初始化逻辑。继承构造派生类通过using Base::Base;直接继承基类的构造函数。两者解决的是不同层面的问题可以配合使用classBase{public:Base(intx):x_(x){}Base():Base(0){}// 委托构造private:intx_;};classDerived:publicBase{public:usingBase::Base;// 继承构造Derived():Base(42){}// 也可以显式委托给基类};6、 委托构造的注意事项异常安全如果目标构造函数抛出异常委托构造函数的函数体不会执行但已构造的成员会被正确析构。调试成本过度使用多层委托可能增加调用链的复杂度建议控制委托层级保持代码可读性。与初始化列表的互斥委托构造时初始化列表只能包含委托调用所有成员初始化都交给目标构造函数完成。性能委托构造不会引入额外的运行时开销编译器通常会将其内联展开。7、总结委托构造是 C11 提供的一项实用特性它让构造函数之间的代码复用变得更加自然和安全。相比传统的init()函数方案委托构造能够正确处理const成员、引用成员等特殊场景同时保持初始化列表的语义完整性。在实际开发中建议将参数最完整、校验最严格的构造函数作为目标构造函数其他构造函数通过委托方式向其靠拢这样既能减少重复代码又能保证所有构造路径都经过统一的初始化逻辑。二、代码示例#includeiostream#includecstdint#includeWindows.hclassParserConfig{public:// 成员包含类内就地初始化(C11)uint32_tbaud_rate{115200};uint8_tparity{0};uint8_tstop_bits{1};constboolenable_checksum;// const成员必须构造阶段初始化// 【构造3全参主构造被别人委托】ParserConfig(uint32_tbaud,uint8_tp,uint8_tstop,boolchk):baud_rate(baud),parity(p),stop_bits(stop),enable_checksum(chk){std::cout[主构造] baud:baud_rate parity:(int)parity stop:(int)stop_bits checksum:enable_checksum\n;}// 【构造2部分参数委托给全参构造】// 初始化列表只写委托不能再写其它成员初始化ParserConfig(uint32_tbaud,boolchk):ParserConfig(baud,0,1,chk)// 委托到上面4参数构造{std::cout[委托构造2] 仅指定波特率校验开关\n;}// 【构造1无参默认构造委托给上面2参数构造多层委托链默认→2参→4参】ParserConfig():ParserConfig(9600,true){std::cout[委托构造1] 默认无参构造\n;}// 示例带explicit 委托防止隐式转换explicitParserConfig(uint32_tbaud):ParserConfig(baud,false){std::cout[explicit委托构造] 单参数波特率\n;}voidprint()const{std::cout baud:baud_rate parity:(int)parity stop:(int)stop_bits checksum:enable_checksum\n\n;}// 错误示范写在这里仅作注释打开会编译报错 #if0// 错误1委托构造不能同时初始化其它成员ParserConfig(inta):ParserConfig(115200,true),parity(1){}// 错误2循环委托 A - B编译报错ParserConfig(char):ParserConfig(0){}ParserConfig(int):ParserConfig(c){}// 错误3不能在函数体内调用其它构造函数这只是创建临时对象不会初始化本对象ParserConfig(double){ParserConfig(115200,true);// 仅仅生成临时对象不会初始化this}#endif};intmain(){SetConsoleOutputCP(CP_UTF8);std::cout 1.无参构造多层委托链默认 →(2参)→(4参)\n;ParserConfig cfg1;cfg1.print();std::cout 2.两参数构造(波特率校验开关) \n;ParserConfigcfg2(460800,false);cfg2.print();std::cout 3.全参直接调用主构造 \n;ParserConfigcfg3(230400,1,2,true);cfg3.print();std::cout 4.explicit单参数委托构造 \n;ParserConfigcfg4(57600);cfg4.print();return0;}
返回列表