《深入理解C++11:C++ 11新特性解析与应用》——2.9 扩展的friend语法

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析DNS,个人版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 本节书摘来自华章计算机《深入理解C++11:C++ 11新特性解析与应用》一书中的第2章,第2.9节,作者 IBM XL编译器中国开发团队,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

2.9 扩展的friend语法

类别:部分人

friend关键字在C++中是一个比较特别的存在。因为我们常常会发现,一些面向对象程序语言,比如Java,就没有定义friend关键字。friend关键字用于声明类的友元,友元可以无视类中成员的属性。无论成员是public、protected或是private的,友元类或友元函数都可以访问,这就完全破坏了面向对象编程中封装性的概念。因此,使用friend关键字充满了争议性。在通常情况下,面向对象程序开发的专家会建议程序员使用Get/Set接口来访问类的成员,但有的时候,friend关键字确实会让程序员少写很多代码。因此即使存在争论,friend还是在很多程序中被使用到。而C++11对friend关键字进行了一些改进,以保证其更加好用。我们可以看看下面的例子,如代码清单2-19所示。

image
image

在代码清单2-19中,我们声明了3个类型:LiLei、Jim和HanMeiMei,它们都有一个友元类型Poly。从编译通过与否的状况中我们可以看出,在C++11中,声明一个类为另外一个类的友元时,不再需要使用class关键字。本例中的Jim和HanMeiMei就是这样一种情况,在HanMeiMei的声明中,我们甚至还使用了Poly的别名P,这同样是可行的。

虽然在C++11中这是一个小的改进,却会带来一点应用的变化—程序员可以为类模板声明友元了。这在C++98中是无法做到的。比如下面这个例子,如代码清单2-20所示。

image

从代码清单2-20中我们看到,对于People这个模板类,在使用类P为模板参数时,P是People

的一个friend类。而在使用内置类型int作为模板参数的时候,People会被实例化为一个普通的没有友元定义的类型。这样一来,我们就可以在模板实例化时才确定一个模板类是否有友元,以及谁是这个模板类的友元。这是一个非常有趣的小特性,在编写一些测试用例的时候,使用该特性是很有好处的。我们看看下面的例子,该例子源自一个实际的测试用例,如代码清单2-21所示。

image
image
image

在代码清单2-21所示的这个例子中,测试人员的目的是在一系列函数调用后,检查Attacker类变量a和Defender类变量d中成员变量的值是否符合预期。这里,按照封装的思想,所有成员变量被声明为private的。但Attacker和Defender的开发者为了方便,并没有为每个成员写Get函数,也没有为Attacker和Defender增加友元定义。而测试人员为了能够快速写出测试程序,采用了比较危险的做法,即使用宏将private关键字统一替换为public关键字。这样一来,类中的private成员就都成了public的。这样的做法存在4个缺点:一是如果侥幸程序中没有变量包含private字符串,该方法可以正常工作,但反之,则有可能导致严重的编译时错误;二是这种做法会降低代码可读性,因为改变了一个常见关键字的意义,没有注意到这个宏的程序员可能会非常迷惑程序的行为;三是如果在类的成员定义时不指定关键字(如public、private、protect等),而使用默认的private成员访问限制,那么该方法也不能达到目的;四则很简单,这样的做法看起来也并不漂亮。

不过由于有了扩展的friend声明,在C++11中,我们可以将Defender和Attacker类改良一下。我们看看下面的例子,如代码清单2-22所示。

image
image
image

在代码清单2-22中,我们把原有的Defender和Attacker类定义为模板类DefenderT和AttackerT。而在需要进行测试的时候,我们使用Validator为模板参数,实例化出DefenderTest及AttackerTest版本的类,这个版本的特点是,Validator是它们的友元,可以任意访问任何成员函数。而另外一个版本则是使用int类型进行实例化的Defender和Attacker,按照C++11的定义,它们不会有友元。因此这个版本保持了良好的封装性,可以用于提供接口用于常规使用。

值得注意的是,在代码清单2-22中,我们使用了using来定义类型的别名,这跟使用typedef的定义类型的别名是完全一样的。使用using定义类型别名是C++11中的一个新特性,我们可以在3.10节中看到相关的描述。

相关文章
|
18天前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
16天前
|
安全 编译器 测试技术
PHP 8新特性解析与应用实践
本文深入探讨了PHP 8的新颖特性,并结合数据和案例分析,展示了这些新特性如何在实际开发中提升代码质量和执行效率。文章不仅涵盖了语言层面的更新,如JIT编译器和联合类型,还讨论了生态系统中的改进,例如改进的错误处理和性能优化技巧。通过逻辑严密的分析,本文旨在为读者提供一份关于PHP 8升级和应用的全面指南。
16 0
|
16天前
|
传感器 存储 数据采集
振弦采集仪的技术解析和应用进行详细介绍
振弦采集仪的技术解析和应用进行详细介绍
振弦采集仪的技术解析和应用进行详细介绍
|
16天前
|
传感器 数据采集 安全
工程安全监测中的振弦采集仪技术解析与应用
工程安全监测中的振弦采集仪技术解析与应用
工程安全监测中的振弦采集仪技术解析与应用
|
1天前
|
存储 SQL 安全
网络安全漏洞解析与加密技术应用
随着信息技术的迅猛发展,网络安全问题日益凸显。本文深入探讨了网络安全漏洞的成因及其对信息安全的影响,重点分析了加密技术在防御网络攻击中的关键作用,同时强调了提升个人和组织安全意识的重要性。通过案例分析和技术讲解,旨在为读者提供全面、深入的网络安全知识分享。
10 2
|
4天前
|
缓存 安全 算法
Java内存模型深度解析与实践应用
本文深入探讨Java内存模型(JMM)的核心原理,揭示其在并发编程中的关键作用。通过分析内存屏障、happens-before原则及线程间的通信机制,阐释了JMM如何确保跨线程操作的有序性和可见性。同时,结合实例代码,展示了在高并发场景下如何有效利用JMM进行优化,避免常见的并发问题,如数据竞争和内存泄漏。文章还讨论了JVM的垃圾回收机制,以及它对应用程序性能的影响,提供了针对性的调优建议。最后,总结了JMM的最佳实践,旨在帮助开发人员构建更高效、稳定的Java应用。
|
4天前
|
算法 编译器 数据处理
PHP 8新特性深度解析与应用实践
本文旨在深入探讨PHP 8的新增特性,并指导如何将这些特性应用于实际开发中。文章将重点介绍JIT编译器、联合类型、命名参数、匹配表达式等关键改进,并通过实例展示它们如何提升代码性能和可读性。读者将了解到这些特性背后的设计哲学及其对PHP未来发展方向的影响。
13 1
|
9天前
|
Java 编译器 程序员
C++中的语法知识虚继承和虚基类
**C++中的多继承可能导致命名冲突和数据冗余,尤其在菱形继承中。为解决这一问题,C++引入了虚继承(virtual inheritance),确保派生类只保留虚基类的一份实例,消除二义性。虚继承通过`virtual`关键字指定,允许明确访问特定路径上的成员,如`B::m_a`或`C::m_a`。这样,即使基类在继承链中多次出现,也只有一份成员副本,简化了内存布局并避免冲突。虚继承应在需要时提前在继承声明中指定,影响到从虚基类派生的所有后代类。**
35 7
|
6天前
|
JavaScript 前端开发 搜索推荐
服务器端渲染技术SSR与ISR:深入解析与应用
【7月更文挑战第20天】服务器端渲染(SSR)和增量静态再生(ISR)作为现代Web开发中的两种重要渲染技术,各有其独特的优势和适用场景。在实际应用中,开发者应根据具体需求和条件选择合适的渲染模式。无论是追求极致的页面加载速度和SEO优化,还是实现内容的实时更新,SSR和ISR都能提供有效的解决方案。通过深入理解这些技术的工作原理和应用场景,开发者可以构建出更加高效、可靠和用户体验优异的Web应用。
|
12天前
|
监控 安全 Linux
Linux命令ssltap的深入解析与应用实践
`ssltap`是一个假想的Linux命令,用于模拟SSL/TLS流量分析。它捕获、解密(如果有密钥)并分析加密流量,提供实时监控、协议解析和安全审计。特点包括实时性、灵活性、可扩展性和安全性。示例用法包括捕获特定端口流量和实时监控会话状态。在实际操作中应注意私钥安全、性能影响及合规性,建议定期审计和自动化监控。

推荐镜像

更多