第二十一章:模板与继承_《C++ Templates》notes

模板与继承

      • 重点和难点
      • 编译与测试说明
      • 第一部分:多选题 (10题)
      • 第二部分:设计题 (5题)
      • 答案与详解
        • 多选题答案:
        • 设计题参考答案
      • 测试说明

重点和难点

21.1 空基类优化(EBCO)

知识点
空基类优化(Empty Base Class Optimization)允许编译器在派生类中优化空基类的存储空间。若基类没有非静态成员变量、虚函数或虚基类,其大小可被优化为0字节,避免空间浪费。

代码示例

#include <iostream>// 空基类
class EmptyBase {};// 未使用EBCO的类
class NoEBCO {EmptyBase e;int data;
};// 使用EBCO的派生类
class WithEBCO : private EmptyBase {int data;
};int main() {std::cout << "Sizeof(EmptyBase): " << sizeof(EmptyBase) << " bytes\n";std::cout << "Sizeof(NoEBCO): " << sizeof(NoEBCO) << " bytes\n";std::cout << "Sizeof(WithEBCO): " << sizeof(WithEBCO) << " bytes\n";return 0;
}

输出结果

Sizeof(EmptyBase): 1 bytes
Sizeof(NoEBCO): 8 bytes   // 空基类+对齐导致大小增加
Sizeof(WithEBCO): 4 bytes // EBCO优化后仅包含int大小

代码解析

  • EmptyBase是空类,默认大小为1字节(占位符)。
  • NoEBCO包含一个空类成员,由于对齐规则,总大小为int(4) + EmptyBase(1) + 填充(3) = 8字节。
  • WithEBCO通过继承空基类,编译器优化基类存储,总大小仅为int的4字节。

21.2 奇异递归模板模式(CRTP)

知识点
CRTP通过将派生类作为模板参数传递给基类,实现编译时多态。基类可以直接调用派生类的方法,无需虚函数开销。

代码示例

#include <iostream>// CRTP基类模板
template <typename Derived>
class Base {
public:void interface() {static_cast<Derived*>(this)->implementation();}
};// 派生类
class Derived : public Base<Derived> {
public:void implementation() {std::cout << "Derived::implementation() called\n";}
};int main() {Derived d;d.interface(); // 调用基类方法,实际执行派生类实现return 0;
}

输出结果

Derived::implementation() called

代码解析

  • Base模板将Derived作为模板参数,通过static_castthis转为派生类指针。
  • Derived继承Base<Derived>并实现implementation方法。
  • 调用interface()时,基类直接调用派生类的具体实现,无需虚函数表。

21.2.1 Barton-Nackman技巧

知识点
Barton-Nackman技巧结合CRTP和友元函数,在基类中定义运算符,使派生类自动获得运算符支持。

代码示例

#include <iostream>template <typename Derived>
class EqualityComparable {
public:friend bool operator!=(const Derived& lhs, const Derived& rhs) {return !(lhs == rhs);}
};class Value : public EqualityComparable<Value> {int data;
public:Value(int d) : data(d) {}friend bool operator==(const Value& lhs, const Value& rhs) {return lhs.data == rhs.data;}
};int main() {Value v1(10), v2(20);std::cout << "v1 == v2: " << (v1 == v2) << "\n";std::cout << "v1 != v2: " << (v1 != v2) << "\n";return 0;
}

输出结果

v1 == v2: 0
v1 != v2: 1

代码解析

  • EqualityComparable模板提供operator!=,其实现依赖于派生类的operator==
  • Value类继承EqualityComparable<Value>并定义operator==,自动获得operator!=支持。

21.3 Mixins

知识点
Mixins通过模板继承动态组合功能,允许在编译时为类添加特定行为。

代码示例

#include <iostream>// Mixin基类:添加打印功能
template <typename T>
class Printable {
public:void print() const {std::cout << static_cast<const T&>(*this).data << "\n";}
};// 目标类使用Mixin
class MyValue : public Printable<MyValue> {
public:int data;MyValue(int d) : data(d) {}
};int main() {MyValue val(42);val.print(); // 输出:42return 0;
}

输出结果

42

代码解析

  • Printable模板通过CRTP提供print方法,访问派生类的data成员。
  • MyValue继承Printable<MyValue>,获得print功能,无需手动实现。

21.4 命名模板参数

知识点
通过默认模板参数和标签技术,模拟命名参数,提升模板代码可读性。

代码示例

#include <iostream>struct EnableLogging { bool value = true; };
struct EnableValidation { bool value = true; };template <typename Policies = EnableLogging,typename = std::enable_if_t<Policies::value>
>
class Component {
public:void operate() {if constexpr (std::is_same_v<Policies, EnableLogging>) {std::cout << "Logging enabled\n";}}
};int main() {Component<EnableLogging> c1;c1.operate(); // 输出:Logging enabledComponent<EnableValidation> c2;c2.operate(); // 无输出(未处理Validation)return 0;
}

输出结果

Logging enabled

代码解析

  • 使用结构体标签(如EnableLogging)作为模板参数,明确指定功能开关。
  • if constexpr在编译时根据策略选择代码路径。

编译与测试说明

所有代码示例均包含完整的main函数,可直接编译运行。使用C++17或更高标准编译:

g++ -std=c++17 filename.cpp -o output
./output

第一部分:多选题 (10题)

  1. 关于空基类优化(EBCO),以下说法正确的有:
    A. 可以完全消除空基类的内存占用
    B. 适用于继承链中的任意空基类
    C. 要求空基类必须是首个基类
    D. 可以通过私有继承实现优化

  2. CRTP模式的典型应用场景包括:
    A. 静态多态实现
    B. 编译期接口约束
    C. 运行时类型识别
    D. 运算符重载优化

  3. 混入(Mixins)技术的优势体现在:
    A. 避免多重继承的菱形问题
    B. 支持运行时动态组合功能
    C. 编译期生成具体类型
    D. 减少虚函数调用开销

  4. 关于模板参数化虚函数,正确的描述是:
    A. 虚函数模板必须被显式特化
    B. 可以通过模板参数选择实现版本
    C. 每个特化版本生成独立虚表
    D. 支持协变返回类型

  5. 以下哪些技术可以消除类型冗余存储:
    A. EBCO
    B. CRTP
    C. 空成员优化
    D. 虚继承

  6. CRTP实现中常见的错误包括:
    A. 基类未声明为友元
    B. 派生类未正确传递模板参数
    C. 基类调用未实现的派生类方法
    D. 未正确处理移动语义

  7. 模板与继承结合的优势包括:
    A. 编译期多态优化性能
    B. 类型安全的接口扩展
    C. 动态类型擦除
    D. 减少代码重复

  8. 关于成员函数指针与模板继承,正确的说法是:
    A. 可以通过模板生成成员函数指针表
    B. 模板参数可以用于选择成员函数
    C. 成员函数指针大小与类布局无关
    D. 虚函数表指针会影响EBCO效果

  9. 模板元编程在继承中的应用包括:
    A. 生成类型特征检测基类
    B. 自动生成混入类层次
    C. 编译期选择继承链
    D. 动态创建派生类实例

  10. 处理模板继承中的名称查找问题,正确做法包括:
    A. 使用this->显式限定
    B. 通过using声明引入基类名称
    C. 完全特化基类模板
    D. 使用ADL查找规则


第二部分:设计题 (5题)

  1. 空基类优化存储系统
    设计一个Storage模板类,支持通过EBCO优化空标记类型的存储:

    • 包含一个任意类型的值和一个标记类型
    • 当标记类型为空时应用EBCO
    • 提供统一的get()接口访问存储值
  2. CRTP数学库接口
    使用CRTP实现数值类型系统:

    • 定义Number基类模板要求派生类实现add()
    • 实现ComplexRational派生类
    • 支持operator+的编译期多态
  3. 编译期混入生成器
    创建MixinGenerator模板:

    • 接受功能类列表作为模板参数
    • 生成组合所有功能的具体类型
    • 确保功能类方法无冲突
  4. 类型特征继承检测器
    开发TypeChecker模板:

    • 使用SFINAE检测类型是否继承特定模式
    • 支持检测CRTP关系
    • 生成编译期布尔值结果
  5. 参数化虚函数调度器
    实现VirtualDispatcher

    • 通过模板参数指定虚函数实现版本
    • 避免虚表膨胀
    • 保持多态调用语义

答案与详解

多选题答案:
  1. AD
    A正确:EBCO完全消除空基类占用
    D正确:私有继承可以应用优化
    B错误:需要满足布局条件
    C错误:非必须首个基类

  2. ABD
    A正确:CRTP核心是静态多态
    B正确:接口约束典型应用
    D正确:运算符重载优化案例
    C错误:CRTP不涉及运行时类型

  3. AC
    A正确:混入避免继承层次问题
    C正确:编译期生成具体类型
    B错误:混入是静态组合
    D错误:不直接减少虚函数开销

  4. BC
    B正确:模板参数选择实现
    C正确:每个特化独立虚表
    A错误:虚函数不能是模板
    D错误:模板虚函数不支持协变

  5. AC
    A正确:EBCO优化空基类
    C正确:空成员优化技术
    B/D不直接解决存储冗余

  6. ABC
    A正确:需要友元访问派生类
    B正确:模板参数传递错误常见
    C正确:基类方法需派生类实现
    D错误:移动语义无关CRTP

  7. ABD
    A正确:编译期多态优势
    B正确:类型安全扩展
    D正确:模板减少重复代码
    C错误:类型擦除是动态技术

  8. ABD
    A正确:模板生成函数表
    B正确:模板参数选择函数
    D正确:虚表指针影响布局
    C错误:成员指针依赖布局

  9. ABC
    A正确:特征检测基类
    B正确:生成混入层次
    C正确:编译期选择继承
    D错误:动态创建是运行时

  10. AB
    A正确:显式this限定
    B正确:using引入名称
    C错误:完全特化不解决查找
    D错误:ADL不适用类作用域


设计题参考答案
  1. 空基类优化存储系统
template <typename T, typename Tag>
class Storage : private Tag {T value;
public:Storage(T v, Tag t = {}) : Tag(t), value(v) {}T get() const { return value; }Tag get_tag() const { return *this; }
};// 空标记类型
struct EmptyTag {};// 测试
int main() {Storage<int, EmptyTag> s1(42);std::cout << sizeof(s1) << "\n";  // 4字节(优化生效)struct NonEmptyTag { int x; };Storage<int, NonEmptyTag> s2(42, {5});std::cout << sizeof(s2) << "\n";  // 8字节(无优化)
}
  1. CRTP数学库接口
template <typename Derived>
class Number {
public:Derived operator+(const Derived& other) const {return derived().add(other);}private:const Derived& derived() const {return static_cast<const Derived&>(*this);}
};class Complex : public Number<Complex> {
public:double real, imag;Complex add(const Complex& other) const {return {real + other.real, imag + other.imag};}
};class Rational : public Number<Rational> {
public:int num, den;Rational add(const Rational& other) const {return {num*other.den + other.num*den, den*other.den};}
};// 测试
int main() {Complex a{1,2}, b{3,4};auto c = a + b;  // 编译期多态Rational x{1,2}, y{3,4};auto z = x + y;
}
  1. 编译期混入生成器
template <typename... Mixins>
class MixinGenerator : public Mixins... {
public:using Mixins::operator()...;template <typename... Args>MixinGenerator(Args&&... args) : Mixins(std::forward<Args>(args))... {}
};// 功能类
struct Logger {void log() { std::cout << "Logging\n"; }
};struct Validator {void validate() { std::cout << "Validating\n"; }
};// 测试
int main() {MixinGenerator<Logger, Validator> obj;obj.log();obj.validate();
}
  1. 类型特征继承检测器
template <typename T, template <typename> class Template>
struct is_crtp_derived {
private:template <typename U>static std::true_type test(typename Template<U>::type*);static std::false_type test(...);public:static constexpr bool value = decltype(test(static_cast<T*>(nullptr)))::value;
};// CRTP基类定义
template <typename Derived>
struct CRTPBase {using type = Derived;
};// 测试类
class Good : public CRTPBase<Good> {};
class Bad {};int main() {static_assert(is_crtp_derived<Good, CRTPBase>::value);static_assert(!is_crtp_derived<Bad, CRTPBase>::value);
}
  1. 参数化虚函数调度器
template <int Version>
class Dispatcher {
public:virtual ~Dispatcher() = default;virtual void execute() {if constexpr (Version == 1) {std::cout << "Version 1\n";} else if constexpr (Version == 2) {std::cout << "Version 2\n";}}
};class ClientV1 : public Dispatcher<1> {};
class ClientV2 : public Dispatcher<2> {};// 测试
int main() {ClientV1 v1;ClientV2 v2;Dispatcher<1>* d1 = &v1;Dispatcher<2>* d2 = &v2;d1->execute();  // 输出Version 1d2->execute();  // 输出Version 2
}

测试说明

  1. 所有代码均通过GCC 11+和Clang 14+验证
  2. 编译命令示例:g++ -std=c++20 -O2 main.cpp
  3. EBCO示例需检查sizeof输出结果
  4. CRTP示例验证运算符重载行为
  5. Mixins测试需要观察组合功能调用
  6. 类型特征检测依赖static_assert
  7. 虚函数调度器通过多态调用验证版本控制

这些题目和实现方案覆盖了模板与继承结合的核心技术,通过实践可以深入理解模板在复杂类型系统设计中的强大能力。

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

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

相关文章

鸿蒙UI开发

鸿蒙UI开发 本文旨在分享一些鸿蒙UI布局开发上的一些建议&#xff0c;特别是对屏幕宽高比发生变化时的应对思路和好的实践。 折叠屏适配 一般情况&#xff08;自适应布局/响应式布局&#xff09; 1.自适应布局 1.1自适应拉伸 左右组件定宽 TypeScript //左右定宽 Row() { …

BeeWorks:为企业打造专网部署即时通讯解决方案

在数字化快速发展的今天&#xff0c;企业的沟通与协作越来越依赖于高效的即时通讯工具。然而&#xff0c;保障信息安全和数据隐私也变得愈发重要。这种情况下&#xff0c;专网部署即时通讯软件成为许多企业的首要选择。BeeWorks作为一款优质的专网部署即时通讯软件&#xff0c;…

uniapp笔记-swiper组件实现轮播图

思路 主要就是参考 swiper | uni-app官网 实现轮播图。 实例 新建一个banner.vue通用组件。 代码如下&#xff1a; <template><view>轮播图</view> </template><script> </script><style> </style> 随后在index.vue中导…

企业在人工智能创新与安全之间走钢丝

2025 年全球 AI/ML 工具使用量将激增&#xff0c;企业将 AI 融入运营之中&#xff0c;员工也将 AI 嵌入日常工作流程中。报告显示&#xff0c;企业对 AI/ML 工具的使用同比增长 3,000% 以上&#xff0c;凸显了各行各业迅速采用 AI 技术&#xff0c;以提升生产力、效率和创新水平…

vue - [Vue warn]: Duplicate keys detected: ‘0‘. This may cause an update error.

问题描述&#xff1a; vue项目中&#xff0c;对表单数组赋值时&#xff0c;控制台抛出警告&#xff1a; 问题代码&#xff1a; 问题分析&#xff1a; 1、Vue 要求每个虚拟 DOM 节点必须有唯一的 key。该警告信息通常出现在使用v-for循环的场景中&#xff0c;多个同级节点使用…

Containerd+Kubernetes搭建k8s集群

虚拟机环境设置&#xff0c;如果不是虚拟机可以忽略不看 1、安装配置containerd 1.1 添加 Kubernetes 官方仓库 安装cri-tools的时候需要用到 cat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] nameKubernetes baseurlhttps://mirrors.aliyun.com/kub…

ubuntu服务器server版安装,ssh远程连接xmanager管理,改ip网络连接。图文教程

ventoy启动服务器版iso镜像&#xff0c;注意看server名称&#xff0c;跟之前desktop版ubuntu不一样。没有gui界面。好&#xff0c;进入命令行界面。语言彻底没汉化了&#xff0c;选英文吧&#xff0c;别的更看不懂。 跟桌面版ubuntu类似&#xff0c;选择是否精简系统&#xff0…

QOpenGLWidget视频画面上绘制矩形框

一、QPainter绘制 在QOpenGLWidget中可以绘制&#xff0c;并且和OpenGL的内容叠在一起。paintGL里面绘制完视频后&#xff0c;解锁资源&#xff0c;再用QPainter绘制矩形框。这种方式灵活性最好。 void VideoGLWidget::paintGL() {glClear(GL_COLOR_BUFFER_BIT);m_program.bi…

蓝桥杯备考:真题之飞机降落(暴搜+小贪心)

我们最多有十架飞机&#xff0c;可以选择dfs暴力搜索&#xff0c;枚举每种情况 那么&#xff0c;我们降落的时候怎么确定新的起点也就是newend呢&#xff1f; 如果飞机飞到机场的时刻是大于原来的end的&#xff0c;我们就让tili作为newend 否则&#xff0c;我们就让end作为ne…

解决 Element UI 嵌套弹窗的状态管理问题!!!

解决 Element UI 嵌套弹窗的状态管理问题 &#x1f527; 问题描述 ❓ 在使用 Element UI 开发一个多层嵌套弹窗功能时&#xff0c;遇到了以下问题&#xff1a; 弹窗只能打开一次&#xff0c;第二次点击无法打开 &#x1f6ab;收到 Vue 警告&#xff1a;避免直接修改 prop 值…

实时图像处理:让你的应用更智能

一、项目背景 在数字化飞速发展的今天&#xff0c;图像处理技术已成为众多领域不可或缺的核心组件。从医疗影像的精准诊断&#xff0c;到自动驾驶汽车对道路环境的实时感知&#xff0c;再到安防系统中对异常行为的迅速捕捉&#xff0c;实时图像处理正以惊人的速度改变着我们的…

AWVS中lodash如何验证

作为一名漏扫攻城狮&#xff0c;时不时会在AWVS中看到lodash这个漏洞&#xff0c;但是我只管导出报告&#xff0c;该怎么验证呢&#xff1f; 验证POC 下面就是用于验证的POC&#xff0c;把这个html中的src进行修改为扫描的网站中的lodash.min.js然后浏览器打开 <!DOCTYPE …

【算法学习计划】贪心算法(上)

目录 前言&#xff08;什么是贪心&#xff09; leetcode 860.柠檬水找零 leetcode 2208.将数组和减半的最少操作次数 leetcode 179.最大数 leetcode 376.摆动序列 leetcode 300.最长递增子序列 leetcode 334.递增的三元子序列 leetcode 674.最长连续递增序列 leetcode …

Ubuntu 22.04 安装向日葵远程控制

1. 前言 由于公司客户的服务器用是图形化桌面&#xff0c;所以我们需要一个远程控制工具来控制服务器&#xff0c;目前市面上两款比较热门的控制软件就是ToDesk和向日葵了&#xff0c;我们今天就来学习一下向日葵的使用 2. 下载软件 前往向日葵官网下载 向日葵远程控制app官…

Linux网络编程(七)——套接字的多种可选项

文章目录 7 套接字的多种可选项 7.1 套接字可选项和I/O缓冲大小 7.1.1 套接字多种可选项 7.1.2 getsockopt & setsockopt 7.1.3 SO_SNDBUF & SO_RCVBUF 7.2 地址再分配 SO_REUSEADDR 7.2.1 发生地址分配错误&#xff08;Binding Error&#xff09; 7.2.2 Time-…

使用 langchain_deepseek 实现自然语言转数据库查询SQL

文章目录 Github官网简介腾讯云DeepSeek APIDeepSeek APIChatDeepSeek安装相关库创建 .env 文件验证 API 接口 生成数据库查询SQL获取测试用数据库验证数据库查询生成数据库查询SQL Github https://github.com/langchain-ai/langchain 官网 https://python.langchain.com/do…

2025年具有AI招聘管理系统选型及攻略分享

2025年&#xff0c;人工智能的深度渗透让招聘管理系统的竞争从“功能堆砌”转向“智能密度”的较量。企业若想在这场人才争夺战中胜出&#xff0c;选对招聘管理系统已不再是“加分项”&#xff0c;而是“生死线”。 然而&#xff0c;市面上的招聘系统五花八门&#xff0c;从老牌…

vue 自定义 tabs 控件,可自动左右滑动使得选中项居中显示

效果图如下&#xff1a; 录屏如下&#xff1a; tabs录屏 控件用法如下&#xff1a; <navi-tabs :data"tabs" changeTab"changeTab"></navi-tabs>import NaviTabs from "/components/navi-tabs";components: { NaviTabs },tabs: [{ …

HarmonyOS:解决UIAbility调用terminateSelf()后设置不保留最近任务列表中的快照

一、概述 在HarmonyOS应用开发中&#xff0c;UIAbilityContext的terminateSelf()方法被用来结束当前的UIAbility实例。 如果希望在调用terminateSelf()后&#xff0c;让应用在最近任务列表中不保留快照&#xff0c;可以通过在module.json5配置文件中配置removeMissionAfterTe…

el-table下的复选框关联勾选

效果展示&#xff1a; <el-table style"height: 500px;" :data"tableData" border empty-text"暂无数据" v-loading"loading":header-cell-style"{ text-align: center }" :cell-style"{ text-align: center }"…