C++那些事之Mixin惯用法

C++那些事之Mixin惯用法

大家好,我是光城,今天给大家分享C++那些事里面的一个惯用法:mixin

混合(Mixins)是Lisp中的一个概念。混合是类的一部分,意味着它旨在与其他类或混合组合在一起。常规独立类(例如Person)与混合的区别在于,混合模拟了一些小功能片段(例如打印或显示),并不用于独立使用。相反,它应该与需要此功能的其他类(例如Person)组合在一起。

因此,混合的目的是允许类似于多重继承的东西。

在C++汇总mixin的基本写法如下:

template <class Super>
class Mixin : public Super {
. /* mixin body */
};

或者

template<typename... Super>
class Mixin : public Super... {public:Mixin() :  Super...() {}// ...
};

注:本节的所有示例代码可从星球获取。

  • C++那些事之Mixin惯用法

  • 示例1:缩放与旋转

  • 示例2:redo与undo

  • 示例3:重复打印

  • 标准库

  • 参考

示例1:缩放与旋转

假设我们要对一个长方形/正方形进行缩放、旋转、添加边框等,这些操作都会影响其宽度与高度,我们可以使用mixin来实现。

首先,我们可以定义好正常形与长方形作为mixin的基类。

// 正方形类
class Square : public Shape {
public:Square(int sideLength) : sideLength(sideLength) {}int GetWidth() const override { return sideLength; }int GetHeight() const override { return sideLength; }
private:int sideLength;
};// 长方形类
class Rectangle : public Shape {
public:Rectangle(int width, int height) : width(width), height(height) {}int GetWidth() const override { return width; }int GetHeight() const override { return height; }
private:int width;int height;
};

随后使用mixin子类去拓展功能,例如:一个缩放的mixin我们可以自定义一个类,它的宽度与高度等于scale乘以对应的宽高。

// 缩放的Mixin
template <class Base, int ScaleX, int ScaleY>
class Scale : public Base {public:int GetScaledWidth() const { return Base::GetWidth() * ScaleX; }int GetScaledHeight() const { return Base::GetHeight() * ScaleY; }
};

像这种场景非常适合使用mixin。

使用的时候:

using ModifiedShape = Border<RotateBy90<Scale<Square, 2, 1>>, 10>;

示例2:redo与undo

完整示例模拟一个redo与undo操作,我们便可以在数据之间来回的切换。Redoable<Undoable<Number>> ,在这里我们可以将这些类混合到一起使用了。

#include <iostream>using namespace std;struct Number {typedef int value_type;int n;void set(int v) {n = v;}int get() const {return n;}
};template <typename BASE, typename T = typename BASE::value_type>
struct Undoable : public BASE {typedef T value_type;T before;void set(T v) {before = BASE::get();BASE::set(v);}void undo() {BASE::set(before);}
};template <typename BASE, typename T = typename BASE::value_type>
struct Redoable : public BASE {typedef T value_type;T after;void set(T v) {after = v;BASE::set(v);}void redo() {BASE::set(after);}
};typedef Redoable<Undoable<Number>> ReUndoableNumber;int main() {ReUndoableNumber mynum;mynum.set(42);mynum.set(84);cout << mynum.get() << '\n';  // Output: 84mynum.undo();cout << mynum.get() << '\n';  // Output: 42mynum.redo();cout << mynum.get() << '\n';  // Output: back to 84
}

示例3:重复打印

再举一个拼积木的例子:重复打印。

首先,有一个类,我们可以print这个人的名字。

class Name
{
public:Name(std::string firstName, std::string lastName): firstName_(std::move(firstName)), lastName_(std::move(lastName)) {}void print() const{std::cout << lastName_ << ", " << firstName_ << '\n';}private:std::string firstName_;std::string lastName_;
};

那如果我想重复打印呢?

我们可以这样玩,使用mixin,将Name类传递进去。

template<typename Printable>
struct RepeatPrint : Printable
{explicit RepeatPrint(Printable const& printable) : Printable(printable) {}void repeat(unsigned int n) const{while (n-- > 0){this->print();}}
};template<typename Printable>
RepeatPrint<Printable> repeatPrint(Printable const& printable)
{return RepeatPrint<Printable>(printable);
}

使用:

Name ned("Eddard", "Stark");    
repeatPrint(ned).repeat(10);

此时,便得到重复n次的打印结果。

那么mixin比较适合什么场景呢?

  • 保持原来的类不变,

  • 客户端代码不直接使用原始类,它需要将其包装到 mixin 中才能使用增强功能,

标准库

在标准库当中有一个使用mixin技术:std::nested_exception。

std::nested_exception 是一个多态 mixin 类,它可以捕获并存储当前异常,从而可以在彼此之间嵌套任意类型的异常。

template <typename _Except>
struct _Nested_exception : public _Except, public nested_exception
{}

在源码中我们可以看到使用了nested_exception作为mixin的基类。

参考

https://cedanet.com.au/ceda/Xc++/$mixin/mixins-in-straight-c++.php

https://www.fluentcpp.com/2017/12/12/mixin-classes-yang-crtp/

https://stackoverflow.com/questions/18773367/what-are-mixins-as-a-concept

1b9fba836d64538003611dd188b79195.png

048a1622ca58394d897008acc50ca915.jpeg

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

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

相关文章

C++学习~~string类

1.STL简单介绍 &#xff08;1&#xff09;标准模版库&#xff0c;是C里面的标准库的一部分&#xff0c;C标准库里面还有其他的东西&#xff0c;但是我们不经常使用&#xff0c;我们经常使用的还是STL这个标准库部分。 &#xff08;2&#xff09;六大件&#xff1a;仿函数&…

内网安全工具之ADExplorer的使用

ADExplorer是域内一款信息查询工具&#xff0c;它是独立的可执行文件&#xff0c;无需安装。它能够列出域组织架构、用户账号、计算机账号登&#xff0c;可以帮助寻找特权用户和数据库服务器等敏感目标。 下载地址&#xff1a;http://live.sysinternals.com/ 连接 下载了ADE…

SSM宠物管理系统-计算机毕业设计源码56932

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对宠物管理系统等问题&#xff0c;对宠物管理…

使用Docker在阿里云ECS上部署Gitlab,提供代码托管、CICD 和 docker镜像服务

文章目录 使用Docker在阿里云ECS上部署Gitlab1.购买一个数据&#xff0c;挂载到/data用于存储gitlab相关数据2. 部署docker引擎3. 调整ssh的默认端口&#xff0c;将22端口留给gitlab4. 部署gitlab5. 进入docker容器获取gitlab的默认密码6. 登录gitlab&#xff0c;完成gitlab-ru…

Spring Boot代码案例(计算器、登录、留言板)

文章目录 一、计算器二、登录2.1 判断账号密码是否正确2.2 根据不同的用户作出不同反应 三、留言板3.1 提交数据3.2 展示所有数据 四、Lombok 工具包4.1 场景介绍4.2 如何使用 五、Edit Starters插件六、项目如何Debug七、项目命名规范 一、计算器 导入前端文件后端代码&#…

Risk Of Rain 雨中冒险2服务器开服联机教程

1、购买后登录服务器&#xff08;百度莱卡云&#xff09; 1.1、第一次购买服务器会安装游戏端&#xff0c;大约5分钟左右&#xff0c;如果长时间处于安装状态请联系客服 2、设置游戏端口 由于雨中冒险2的设置需要两个端口&#xff0c;它们用于游戏端口&#xff0c;查询端口&am…

理解 Python 中的 `super()` 与 `__init__()` 方法

在 Python 的面向对象编程中&#xff0c;super() 函数和 __init__() 方法是两个非常重要的概念。它们在类的继承和初始化过程中扮演着关键的角色。本文将深入探讨这两个概念的工作原理&#xff0c;并通过示例代码来展示它们的使用。 基本原理 __init__() 方法 __init__() 是…

K8S认证 | CKA题库 + 答案 | 查看Pod CPU资源使用量

2、查看集群中运行Pod CPU资源使用量 您必须在以下Cluster/Node上完成此考题&#xff1a; Cluster Master node Worker node k8s …

Vitis HLS 学习笔记--资源绑定-使用URAM(1)

目录 1. 简介 2. 代码分析 2.1 存储器代码 2.2 Implementation报告 2.3 存储器类型指定 2.4 存储器初始化 3. 总结 1. 简介 在博文《Vitis HLS 学习笔记--资源绑定-使用URAM-CSDN博客》中&#xff0c;介绍了如何在Vitis HLS环境下设计一个简易的存储器模型。 通过以下…

贝努利贝叶斯算法

基本用法 完整代码&#xff1a; from sklearn.naive_bayes import BernoulliNB from sklearn.datasets import make_blobs from sklearn.model_selection import train_test_split# 生成数据 X, y make_blobs(n_samples500, centers5, random_state8) X_train, X_test, y_tr…

企业或者个体户为什么会经营异常?

在复杂多变的市场经济环境中&#xff0c;无论是企业还是个体工商户&#xff0c;都可能遭遇经营异常的情况。及时识别这些预警信号并采取有效措施&#xff0c;对于避免潜在风险、保持健康发展至关重要。本文将深入探讨企业与个体户常见的经营异常类型、识别方法以及应对策略&…

MongoDB的安装和配置

简介 MongoDB 是一个开源的、面向文档的、非关系型数据库管理系统&#xff08;NoSQL&#xff09;。它使用JSON-like&#xff08;BSON&#xff09;文档来存储数据&#xff0c;使得数据结构更加灵活&#xff0c;易于理解和操作&#xff0c;特别适合处理大量的、半结构化或非结构…