《深入理解C++11:C++ 11新特性解析与应用》——第3章 通用为本,专用为末 3.1 继承构造函数

简介: 本节书摘来自华章计算机《深入理解C++11:C++ 11新特性解析与应用》一书中的第3章,第3.1节,作者 IBM XL编译器中国开发团队,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

第 3 章

通用为本,专用为末

C++11的设计者总是希望从各种方案中抽象出更为通用的方法来构建新的特性。这意味着C++11中的新特性往往具有广泛的可用性,可以与其他已有的,或者新增的语言特性结合起来进行自由的组合,或者提升已有特性的通用性。这与在语言缺陷上“打补丁”的做法有着本质的不同,但也在一定程度上拖慢了C++11标准的制定。不过现在一切都已经尘埃落定了。在本章里读者可以看到这些经过反复斟酌制定的新特性,并体会其“普适”的特性。当然,要对一些形如右值引用、移动语义的复杂新特性做到融会贯通,则需要读者反复揣摩。

3.1 继承构造函数

类别:类作者

C++中的自定义类型—类,是C++面向对象的基石。类具有可派生性,派生类可以自动获得基类的成员变量和接口(虚函数和纯虚函数,这里我们指的都是public派生)。不过基类的非虚函数则无法再被派生类使用了。这条规则对于类中最为特别的构造函数也不例外,如果派生类要使用基类的构造函数,通常需要在构造函数中显式声明。比如下面的例子:

struct A { A(int i) {} };
struct B : A { B(int i): A(i) {} };

B派生于A,B又在构造函数中调用A的构造函数,从而完成构造函数的“传递”。这在C++代码中非常常见。当然,这样的设计有一定的好处,尤其是B中有成员的时候。如代码清单3-1所示的例子。

image

在代码清单3-1中我们看到,派生于结构体A的结构体B拥有一个成员变量d,那么在B的构造函数B(int i)中,我们可以在初始化其基类A的同时初始化成员d。从这个意义上讲,这样的构造函数设计也算是非常合理的。

不过合情合理并不等于合用,有的时候,我们的基类可能拥有数量众多的不同版本的构造函数—这样的情况并不少见,我们在2.7节中就曾经看到过这样的例子。那么倘若基类中有大量的构造函数,而派生类却只有一些成员函数时,那么对于派生类而言,其构造就等同于构造基类。这时候问题就来了,在派生类中我们写的构造函数完完全全就是为了构造基类。那么为了遵从于语法规则,我们还需要写很多的“透传”的构造函数。我们可以看看下面这个例子,如代码清单3-2所示。

image

在代码清单3-2中,我们的基类A有很多的构造函数的版本,而继承于A的派生类B实际上只是添加了一个接口ExtraInterface。那么如果我们在构造B的时候想要拥有A这样多的构造方法的话,就必须一一“透传”各个接口。这无疑是相当不方便的。

事实上,在C++中已经有了一个好用的规则,就是如果派生类要使用基类的成员函数的话,可以通过using声明(using-declaration)来完成。我们可以看看下面这个例子,如代码清单3-3所示。

image
image

在代码清单3-3中,我们的基类Base和派生类Derived声明了同名的函数f,不过在派生类中的版本跟基类有所不同。派生类中的f函数接受int类型为参数,而基类中接受double类型的参数。这里我们使用了using声明,声明派生类Derived也使用基类版本的函数f。这样一来,派生类中实际就拥有了两个f函数的版本。可以看到,我们在main函数中分别定义了Base变量b和Derived变量d,并传入浮点字面常量4.5,结果都会调用到基类的接受double为参数的版本。

在C++11中,这个想法被扩展到了构造函数上。子类可以通过使用using声明来声明继承基类的构造函数。那我们要改造代码清单3-2所示的例子就非常容易了,如代码清单3-4所示。

image

这里我们通过using A::A的声明,把基类中的构造函数悉数继承到派生类B中。这样我们在代码清单3-2中的“透传”构造函数就不再需要了。而且更为精巧的是,C++11标准继承构造函数被设计为跟派生类中的各种类默认函数(默认构造、析构、拷贝构造等)一样,是隐式声明的。这意味着如果一个继承构造函数不被相关代码使用,编译器不会为其产生真正的函数代码。这无疑比“透传”方案总是生成派生类的各种构造函数更加节省目标代码空间。

不过继承构造函数只会初始化基类中成员变量,对于派生类中的成员变量,则无能为力。不过配合我们2.7节中的类成员的初始化表达式,为派生类成员变量设定一个默认值还是没有问题的。

在代码清单3-5中我们就同时使用了继承构造函数和成员变量初始化两个C++11的特性。这样就可以解决一些继承构造函数无法初始化的派生类成员问题。如果这样仍然无法满足需求的话,程序员只能自己来实现一个构造函数,以达到基类和成员变量都能够初始化的目的。

image

有的时候,基类构造函数的参数会有默认值。对于继承构造函数来讲,参数的默认值是不会被继承的。事实上,默认值会导致基类产生多个构造函数的版本,这些函数版本都会被派生类继承。比如代码清单3-6所示的这个例子。

image

可以看到,在代码清单3-6中,我们的基类的构造函数A (int a = 3, double = 2.4)有一个接受两个参数的构造函数,且两个参数均有默认值。那么A到底有多少个可能的构造函数的版本呢?

事实上,B可能从A中继承来的候选继承构造函数有如下一些:

image

相应地,B中的构造函数将会包括以下一些:

image

可以看见,参数默认值会导致多个构造函数版本的产生,因此程序员在使用有参数默认值的构造函数的基类的时候,必须小心。

而有的时候,我们还会遇到继承构造函数“冲突”的情况。这通常发生在派生类拥有多个基类的时候。多个基类中的部分构造函数可能导致派生类中的继承构造函数的函数名、参数(有的时候,我们也称其为函数签名)都相同,那么继承类中的冲突的继承构造函数将导致不合法的派生类代码,如代码清单3-7所示。

image

在代码清单3-7中,A和B的构造函数会导致C中重复定义相同类型的继承构造函数。这种情况下,可以通过显式定义继承类的冲突的构造函数,阻止隐式生成相应的继承构造函数来解决冲突。比如:

struct C: A, B {
    using A::A;
    using B::B;
    C(int){}
};

其中的构造函数C(int)就很好地解决了代码清单3-7中继承构造函数的冲突问题。

另外我们还需要了解的一些规则是,如果基类的构造函数被声明为私有成员函数,或者派生类是从基类中虚继承的,那么就不能够在派生类中声明继承构造函数。此外,如果一旦使用了继承构造函数,编译器就不会再为派生类生成默认构造函数了,那么形如代码清单3-8中这样的情况,程序员就必须注意继承构造函数没有包含一个无参数的版本。在本例中,变量b的定义应该是不能够通过编译的。

image

在我们编写本书的时候,还没有编译器实现了继承构造函数这个特性,所以本节中代码清单3-4至代码清单3-8的例子都仅供读者参考,因为我们并没有实际编译过。但是编译器对继承构造函数的支持应该很快就要完成了,比如g++就计划在4.8版本中提供支持。可能本书出版的时候,读者就已经可以进行实验了。

相关文章
|
3月前
|
机器学习/深度学习 文字识别 监控
安全监控系统:技术架构与应用解析
该系统采用模块化设计,集成了行为识别、视频监控、人脸识别、危险区域检测、异常事件检测、日志追溯及消息推送等功能,并可选配OCR识别模块。基于深度学习与开源技术栈(如TensorFlow、OpenCV),系统具备高精度、低延迟特点,支持实时分析儿童行为、监测危险区域、识别异常事件,并将结果推送给教师或家长。同时兼容主流硬件,支持本地化推理与分布式处理,确保可靠性与扩展性,为幼儿园安全管理提供全面解决方案。
166 3
|
4月前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
119 15
|
5月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
4月前
|
人工智能 API 开发者
HarmonyOS Next~鸿蒙应用框架开发实战:Ability Kit与Accessibility Kit深度解析
本书深入解析HarmonyOS应用框架开发,聚焦Ability Kit与Accessibility Kit两大核心组件。Ability Kit通过FA/PA双引擎架构实现跨设备协同,支持分布式能力开发;Accessibility Kit提供无障碍服务构建方案,优化用户体验。内容涵盖设计理念、实践案例、调试优化及未来演进方向,助力开发者打造高效、包容的分布式应用,体现HarmonyOS生态价值。
194 27
|
3月前
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
82 4
|
4月前
|
供应链 项目管理 容器
深入探索 BPMN、CMMN 和 DMN:从定义到应用的全方位解析
在当今快速变化的商业环境中,对象管理组织(OMG)推出了三种强大的建模标准:BPMN(业务流程模型和符号)、CMMN(案例管理模型和符号)和DMN(决策模型和符号)。它们分别适用于结构化流程管理、动态案例处理和规则驱动的决策制定,并能相互协作,覆盖更广泛的业务场景。BPMN通过直观符号绘制固定流程;CMMN灵活管理不确定的案例;DMN以表格形式定义清晰的决策规则。三者结合可优化企业效率与灵活性。 [阅读更多](https://example.com/blog)
深入探索 BPMN、CMMN 和 DMN:从定义到应用的全方位解析
|
4月前
|
存储 弹性计算 安全
阿里云服务器ECS通用型规格族解析:实例规格、性能基准与场景化应用指南
作为ECS产品矩阵中的核心序列,通用型规格族以均衡的计算、内存、网络和存储性能著称,覆盖从基础应用到高性能计算的广泛场景。通用型规格族属于独享型云服务器,实例采用固定CPU调度模式,实例的每个CPU绑定到一个物理CPU超线程,实例间无CPU资源争抢,实例计算性能稳定且有严格的SLA保证,在性能上会更加稳定,高负载情况下也不会出现资源争夺现象。本文将深度解析阿里云ECS通用型规格族的技术架构、实例规格特性、最新价格政策及典型应用场景,为云计算选型提供参考。
|
4月前
|
数据采集 机器学习/深度学习 存储
可穿戴设备如何重塑医疗健康:技术解析与应用实战
可穿戴设备如何重塑医疗健康:技术解析与应用实战
157 4
|
4月前
|
人工智能 自然语言处理 算法
DeepSeek大模型在客服系统中的应用场景解析
在数字化浪潮下,客户服务领域正经历深刻变革,AI技术成为提升服务效能与体验的关键。DeepSeek大模型凭借自然语言处理、语音交互及多模态技术,显著优化客服流程,提升用户满意度。它通过智能问答、多轮对话引导、多模态语音客服和情绪监测等功能,革新服务模式,实现高效应答与精准分析,推动人机协作,为企业和客户创造更大价值。
442 5
|
4月前
|
机器学习/深度学习 JSON 算法
淘宝拍立淘按图搜索API接口系列的应用与数据解析
淘宝拍立淘按图搜索API接口是阿里巴巴旗下淘宝平台提供的一项基于图像识别技术的创新服务。以下是对该接口系列的应用与数据解析的详细分析

推荐镜像

更多
  • DNS