Effective C++学习笔记(7)

目录

  • 条款41:了解隐式接口和编译多态
  • 条款42:了解typename的双重意义
  • 条款43:学习处理模板化基类内的名称
  • 条款44:将与参数无关的代码抽离templates
  • 条款45:运用成员函数模板接受所有兼容类型
  • 条款46:需要类型转换时请为模板定义非成员函数
  • 条款47:请使用traits classes表现类型信息
  • 条款48:认识模板元编程

条款41:了解隐式接口和编译多态

  • 显示接口:在源码中可以找到明确可见的函数接口。
    在这里插入图片描述

- 隐式接口:不是基于函数签名式,而是有效表达式组成的接口。如下图,函数接口最终实例化成什么函数和模板参数T有关,在代码编译之前是不确定的。
在这里插入图片描述

  • 运行期多态:在运行期虚函数指针根据指向对象确定哪一个虚函数该被绑定调用。
  • 编译期多态:在编译期以不同的模板参数具现化会导致调用不同的函数。
  • 对classes而言接口是显式的(explicit),以函数签名为中心。多态则是通过 virtual函数发生于运行期
  • 对template参数而言,接口是隐式的(implicit),奠基于有效表达式。多态则是通过template具现化和函数重载解析(function overloading resolution)发生于编译期

条款42:了解typename的双重意义

  • 当声明template类型参数时,class和typename意义完全相同。建议使用typename
  • template内出现的名称如果相依于某个template参数,称之为从属名称(dependent names)。如果从属名称在 class内呈嵌套状,我们称它为嵌套从属名称(nested dependent name)。
  • 当嵌套从属名称表示一个类型时,需要加上typename前缀,表示是一个类型,也叫做嵌套从属类型名称;如果不加typename前缀,默认这个嵌套从属名称是一个非类型(例如某个类的静态成员变量C::value)。
    在这里插入图片描述
    在这里插入图片描述
  • “typename必须作为嵌套从属类型名称的前缀词”这一规则的例外是,**typename不可以出现在base classes list内的嵌套从属类型名称之前,也不可在member initialization list(成员初值列)中作为base class修饰符。**例如:
    在这里插入图片描述
  • 对于冗长的嵌套从属类型名称可用typedef简化
    在这里插入图片描述

条款43:学习处理模板化基类内的名称

  • C++拒绝这个调用的原因:它知道base class templates有可能被特化,而那个特化版本可能不提供和一般性 template相同的接口。因此它往往拒绝在 templatized base classes(模板化基类,本例的MsgSender)内寻找继承而来的名称(本例的 sendClear)。实例化前编译器不进入base class作用域内查找。就某种意义而言,当我们从Object Oriented C++跨进Template C++,继承就不像以前那般畅行无阻了。
    在这里插入图片描述

  • 解决方法统一思路:对编译器承诺“base class template的任何特化版本都将支持其一般(泛化)版本所提供的接口”。

  • 解决方法1:在base class 函数调用动作之前加上“this->”
    在这里插入图片描述

  • 解决方法2:使用using声明式提前声明模板基类函数
    在这里插入图片描述

  • 解决方法3(不推荐):明确指出调用的函数位于模板基类里。若调用的是virtual函数,这种明确修饰会关闭“virtual绑定行为”(只会调用基类的虚函数,而不会调用继承类中对应重写的虚函数):
    在这里插入图片描述

  • 编译器的诊断时间可能发生在早期(当解析derived class template 的定义式时),也可能发生在晚期(当那些templates被特定之template 实参具现化时)。C++的政策是宁愿较早诊断,这就是为什么“当base classes 从templates中被具现化时”
    它假设它对那些baseclasses的内容毫无所悉的缘故。

条款44:将与参数无关的代码抽离templates

  • 模板代码膨胀:其二进制码带着重复(或几乎重复)的代码、数据,或两者。其结果有可能源码看起来合身而整齐,但目标码(object code) 却不是那么回事。
  • Templates生成多个classes和多个函数,所以任何template代码都不该与某个造成膨胀的template参数产生相依关系。
  • 非类型模板参数(non- type template parameters) 而造成的代码膨胀,往往可消除,做法是以函数参数或class成员变量替换template参数
  • 类型参数(type parameters)而造成的代码膨胀,往往可降低,做法是让带有完全相同二进制表述( binary representations)的具现类型( instantiation types)共享实现码
  • 有时愈是尝试精密的做法,事情变得愈是复杂。从某个角度看,一点点代码重复反倒看起来有点幸运了。需要在具体不同平台进行衡量。

条款45:运用成员函数模板接受所有兼容类型

  • 以智能指针是“行为像指针”的对象,讨论如何实现成员函数模板用于接受所有兼容类型,泛化智能指针操作类似指针操作。
  • 通过成员函数模板建立一个泛化的copy构造函数,使得该拷贝构造函数可以支持智能指针隐式转换。这个行为只有当“存在某个隐式转换可将-一个U指针转为-一个T指针”时才能通过编译,而那正是我们想要的。这个构造函数只在其所获得的实参隶属适当(兼容)类型时才通过编译:
    在这里插入图片描述
  • 通过成员函数模板建立一个泛化的赋值操作“=”函数。下图所有构造函数都是explicit, 惟有“泛化copy构造函数”除外。那意味从某个shared_ ptr 类型隐式转换至另一个shared ptr 类型是被允许的,但从某个内置指针或从其他智能指针类型进行隐式转换则不被认可(如果是显式转换如cast强制转型动作倒是可以)。
    在这里插入图片描述
  • member templates 并不改变语言规则,而语言规则说,如果程序需要一个copy构造函数,你却没有声明它,编译器会为你暗自生成一个。 在class内声明泛化copy构造函数(是个member template)并不会阻止编译器生成它们自己的copy构造函数(一个non-template),所以如果你想要控制copy构造的方方面面,你必须同时声明泛化copy构造函数和“正常的”copy构造函数。相同规则也适用于赋值( assignment)操作
    在这里插入图片描述

条款46:需要类型转换时请为模板定义非成员函数

  • 模板中,根据实参推导模板参数类型时不支持隐式类型转换推导。如果一个模板类中,模板内的函数需要参数类型转换,成员函数无法做到。函数参数隐式类型转换之前需要确定该函数存在,而实例化之前成员函数并不存在。
  • 可在模板类内中采用friend函数声明和定义,使其声明跟随模板类一起实例化,之后再调用的时候就可以自动找到该函数的声明,进行隐式类型转换(下图中可在*重载中输入int类型数据,使其隐式调用Rational的int类型构造函数,隐式转换为Rational<int>)。
    在这里插入图片描述
  • 由于定义于class内中的函数暗自成为inline,可采用class内中friend函数啥也不干,只调用一个外部辅助函数即可,减小inline声明所带来的冲击
    在这里插入图片描述

条款47:请使用traits classes表现类型信息

  • STL中迭代器可分为五类,继承关系如下图:
    (1). Input 迭代器,只能一步一步向前移动,只能读取内容,且仅读取一次。
    (2). Output 迭代器,只能一步一步向前移动,只能写入内容,且仅写入一次。
    (3). Forward 迭代器,只能一步一步向前移动,可读可写多次。
    (4). Bidirectianol 迭代器,只能一步一步向前或向后移动,可读可写多次。
    (5). Random Access 迭代器,可以在常量时间以任意步数向前或向后移动,可读可写多次。

在这里插入图片描述

  • Traits是一种技术,也是一个C++程序员共同遵守的协议。它对内置类型和用户自定义类型的表现必须一样好

  • Traits设计实现流程(例子是实现advance模板函数,可以接受各种类型的迭代器进行移动):
    -(1)确认若干你希望将来可取得的类型信息;
    -(2)为该信息选一个名称;
    在这里插入图片描述
    -(3)提供一个template和一组特例化版本( 例特例化内置指针类型):
    在这里插入图片描述
    在这里插入图片描述

  • Traits classes使得“类型相关信息”在编译期可用。它们以templates和“templates特化”完成实现。整合重载技术( overloading) 后,traitsclasses有可能在编译期对类型执行if…else测试。(上述advance中有类型条件判单,是在运行期执行,可采用重载技术使其在编译期进行,仅在advance函数中调用重载函数即可,如下图)。
    在这里插入图片描述

在这里插入图片描述

  • 如何使用一个traits class:
    (1)建立一组重载函数 (身份像劳工)或函数模板(例如doAdvance) ,彼此间的差异只在于各自的traits参数。令每个函数实现码与其接受之traits信息相应和。.
    (2)建立一个控制函数 (身份像工头)或函数模板(例如advance) ,它调用上述那些“劳工函数”并传递traits class所提供的信息。

条款48:认识模板元编程

  • Template metaprogramming (TMP,模板元编程)可将工作由运行期移往编译期,因而得以实现早期错误侦测和更高的执行效率。
  • TMP可被用来生成“基于政策选择组合”的客户定制代码,也可用来避免生成对某些特殊类型并不适合的代码。
  • 由于template metaprograms执行于C++编译期,因此可将工作从运行期转移到编译期。这导致的一个结果是,某些错误原本通常在运行期才能侦测到,现在可在编译期找出来。另一一个结果是,使用TMP的C++程序可能在每一方面都更高效:较小的可执行文件、较短的运行期、较少的内存需求。然而将工作从运行期移转至编译期的另一个结果是,编译时间变长了
  • TMP中if…else…可通过模板函数重载实现;TMP循环结构可使用递归;TMP递归涉及递归模板具现化,如下图计算阶乘:
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/70948.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git日常操作-案例

文章目录 查看tag对应版本tag一个版本切换到指定tag查看远程有那些分支 查看tag对应版本 要查看 Git 仓库中标签&#xff08;tag&#xff09;对应的版本&#xff0c;可以使用以下命令&#xff1a; git show <tag>将 替换为你要查看的标签名称。该命令将显示与标签对应的…

Vue3和Vue2对比学习之全局 API 应用实例

文章目录 0.前言1.参考文档2.详细说明2.1 全局 API 应用实例 非兼容2.2 一个新的全局 API&#xff1a;createAppconfig.productionTip 移除config.ignoredElements 替换为 config.isCustomElementVue.prototype 替换为 config.globalPropertiesVue.extend 移除类型推断组件继承…

【FastColoredTextBox】C# 开源文本编辑控件

主界面截图 使用Demos演示 FastColoredTextBox 是一个用于在 C# 程序中实现高亮语法着色、代码编辑和文本显示的自定义控件。它提供了许多功能&#xff0c;包括&#xff1a; 语法高亮&#xff1a;FastColoredTextBox 支持多种语言的语法高亮&#xff0c;可以根据语法规则将不同…

LinuxC编程——进程

目录 一、概念1.1 程序1.2 进程 二、特点⭐⭐⭐三、进程段四、进程分类五、进程状态六、进程状态转换图七、函数接口1. 创建子进程2. 回收进程资源3. 退出进程4. 获取进程号 八、守护进程 一、概念 进程和程序是密不可分的两组概念&#xff0c;相对比&#xff0c;便于理解。 1.…

ndk开发-交叉编译

为什么要使用交叉编译&#xff1a; 在linux系统一般使用c c编译可执行程序或者so库文件。该程序只能在当前linux系统执行&#xff0c;为了将生成文件可以再android平台运行&#xff0c;必须使用交叉编译。ndk中提供了跟多android平台交叉编译链&#xff0c;所以首先下载ndk工具…

【JUC】线程池ThreadPoolTaskExecutor与面试题解读

1、ThreadPoolTaskExecutor 创建线程池 从它的创建和使用说起&#xff0c;创建和使用的代码如下&#xff1a; 创建&#xff1a; ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();executor.setCorePoolSize(corePoolSize);executor.setMaxPoolSize(maxPoolSize…

Yii2 advanced 框架,自定义Log日志方案

背景 近期在使用 【Yii2 advanced】框架时 在接触到 微信支付回调操作时&#xff0c;想要将微信服务器请求的参数信息记录下来 但是&#xff0c;不喜欢框架自带的日志配置方式 在此&#xff0c;推荐使用一种自定义文件目录与log记录形式的方案 希望有此需求的道友&#xff0c;能…

团团代码生成器V1.0:一键生成完整的CRUD功能(提供Gitee源码)

前言&#xff1a;在日常开发的中&#xff0c;经常会需要重复写一些基础的增删改查接口&#xff0c;虽说不难&#xff0c;但是会耗费我们一些时间&#xff0c;所以我自己开发了一套纯SpringBoot实现的代码生成器&#xff0c;可以为我们生成单条数据的增删改查&#xff0c;还可以…

ArcGIS Pro基础入门、制图、空间分析、影像分析、三维建模、空间统计分析与建模、python融合、案例全流程科研能力提升

目录 第一章 入门篇 GIS理论及ArcGIS Pro基础 第二章 基础篇 ArcGIS数据管理与转换 第三章 数据编辑与查询、拓扑检查 第四章 制图篇 地图符号与版面设计 第五章 空间分析篇 ArcGIS矢量空间分析及应用 第六章 ArcGIS栅格空间分析及应用 第七章 影像篇 遥感影像处理 第八…

Java基础知识实际应用(学生信息管理系统、猜拳小游戏、打印日历)

一、Java学生信息管理系统 这个系统包含了添加、修改、删除、查询和显示所有学生信息等功能。您可以在此基础上进行修改和完善&#xff0c;以适应您的需求。 import java.util.Scanner;public class StudentManagementSystem {private static Scanner scanner new Scanner(S…

分布式作业调度框架——ElasticJob

1、简介 ElasticJob 是面向互联网生态和海量任务的分布式调度解决方案&#xff0c;由两个相互独立的子项目 ElasticJob-Lite 和 ElasticJob-Cloud 组成。 它通过弹性调度、资源管控、以及作业治理的功能&#xff0c;打造一个适用于互联网场景的分布式调度解决方案&#xff0c;…

内网穿透——使用Windows自带的网站程序建立网站

文章目录 1.前言2.Windows网页设置2.1 Windows IIS功能设置2.2 IIS网页访问测试 3. Cpolar内网穿透3.1 下载安装Cpolar3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5.结语 1.前言 在网上各种教程和介绍中&#xff0c;搭建网页都会借助各种软件的帮助&#xff0c;比如…