Effective C++ 规则46: 需要类型转换时,请为模板定义非成员函数

1、背景

在 C++ 中,类型转换分为隐式类型转换和显式类型转换。隐式类型转换主要通过构造函数或转换运算符完成。当你定义一个成员函数时(如操作符重载),编译器通常只能对非第一个参数进行隐式类型转换

2、不按规则写代码的问题

示例代码如下:

#include <iostream>template <typename T>
class Rational {
public:Rational(T numerator = 0, T denominator = 1): numerator_(numerator), denominator_(denominator) {}// 成员函数重载 +Rational operator+(const Rational& rhs) const {return Rational(numerator_ * rhs.denominator_ + rhs.numerator_ * denominator_,denominator_ * rhs.denominator_);}private:T numerator_;T denominator_;
};int main() {Rational<int> r1(1, 2);    // 1/2Rational<int> r2 = r1 + 2; // 正确Rational<int> r2 = 2 + r1; // 错误,2 无法隐式转换为 Rational<int>return 0;
}

因为operator+是成员函数,编译器不支持对第一个参数进行隐式类型转换,也就谁说,不能将2隐士转成Ratioanl并和this绑定,因此会出现编译错误。

3、解决方案

  • 将成员函数定义为非成员函数,将 + 定义为非成员函数可以解决问题,因为对于非成员函数,编译器允许对所有参数进行隐式类型转换。
#include <iostream>template <typename T>
class Rational {
public:Rational(T numerator = 0, T denominator = 1): numerator_(numerator), denominator_(denominator) {}// 访问私有成员的接口T numerator() const { return numerator_; }T denominator() const { return denominator_; }private:T numerator_;T denominator_;
};// 非成员函数重载 +
template <typename T>
Rational<T> operator+(const Rational<T>& lhs, const Rational<T>& rhs) {return Rational<T>(lhs.numerator() * rhs.denominator() + rhs.numerator() * lhs.denominator(),lhs.denominator() * rhs.denominator());
}int main() {Rational<int> r1(1, 2);    // 1/2Rational<int> r2 = r1 + 2; // OK,2 被隐式转换为 Rational<int>Rational<int> r3 = 2 + r1; // OK,同样支持std::cout << "Success!" << std::endl;return 0;
}

operator+ 是非成员函数,因此编译器允许 2 被隐式转换为 Rational,无论操作数的顺序如何(如 r1 + 2 或 2 + r1),非成员函数都可以正常工作。

  • 利用友元函数将非成员函数声明为模板类的友元。
#include <iostream>template <typename T>
class Rational {
public:Rational(T numerator = 0, T denominator = 1): numerator_(numerator), denominator_(denominator) {}private:T numerator_;T denominator_;// 友元函数friend Rational operator+(const Rational& lhs, const Rational& rhs) {return Rational(lhs.numerator_ * rhs.denominator_ + rhs.numerator_ * lhs.denominator_,lhs.denominator_ * rhs.denominator_);}
};int main() {Rational<int> r1(1, 2);Rational<int> r2 = r1 + 2; // OKRational<int> r3 = 2 + r1; // OKstd::cout << "Success!" << std::endl;return 0;
}

在这种方式中,operator+ 是 Rational 类的友元,可以直接访问私有成员,同时仍然支持隐式类型转换。

4、总结

  • 支持隐式类型转换:非成员函数允许对所有参数进行隐式类型转换,而成员函数只能对非 this 参数进行转换。
  • 提升灵活性:非成员函数可以更好地处理多种操作数的组合。
  • 友元函数的封装性:使用友元可以在保持封装的同时,让非成员函数访问类的私有数据。
    这条规则的核心思想是:当操作符重载需要支持隐式类型转换时,选择非成员函数更合适,尤其是在模板类中。

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

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

相关文章

GIS 中的 SQLAlchemy:空间数据与数据库之间的桥梁

利用 SQLAlchemy 在现代应用程序中无缝集成地理空间数据导言 地理信息系统&#xff08;GIS&#xff09;在管理城市规划、环境监测和导航系统等各种应用的空间数据方面发挥着至关重要的作用。虽然 PostGIS 或 SpatiaLite 等专业地理空间数据库在处理空间数据方面非常出色&#…

Jmeter使用Request URL请求接口

简介 在Jmeter调试接口时&#xff0c;有时不清楚后端服务接口的具体路径&#xff0c;可以使用Request URL和cookie来实现接口请求。以下内容以使用cookie鉴权的接口举例。 步骤 ① 登录网站后获取具体的Request URL和cookie信息 通过浏览器获取到Request URL和cookie&#…

每日十题八股-2025年1月24日

1.面试官&#xff1a;Kafka 百万消息积压如何处理&#xff1f; 2.面试官&#xff1a;最多一次、至少一次和正好一次有什么区别? 3.面试官&#xff1a;你项目是怎么存密码的? 4.面试官&#xff1a;如何设计一个分布式ID&#xff1f; 5.面试官&#xff1a;单点登录是怎么工作的…

Docker—搭建Harbor和阿里云私有仓库

Harbor概述 Harbor是一个开源的企业级Docker Registry管理项目&#xff0c;由VMware公司开发。‌它的主要用途是帮助用户迅速搭建一个企业级的Docker Registry服务&#xff0c;提供比Docker官方公共镜像仓库更为丰富和安全的功能&#xff0c;特别适合企业环境使用。‌12 Harb…

基于Docker的Spark分布式集群

目录 1. 说明 2. 服务器规划 3. 步骤 3.1 要点 3.2 配置文件 3.2 访问Spark Master 4. 使用测试 5. 参考 1. 说明 以docker容器方式实现apache spark计算集群&#xff0c;能灵活的增减配置与worker数目。 2. 服务器规划 服务器 (1master, 3workers) ip开放端口备注ce…

C语言自定义数据类型详解(一)——结构体类型(上)

什么是自定义数据类型呢&#xff1f;顾名思义&#xff0c;就是我们用户自己定义和设置的类型。 在C语言中&#xff0c;我们的自定义数据类型一共有三种&#xff0c;它们分别是&#xff1a;结构体(struct)&#xff0c;枚举(enum)&#xff0c;联合(union)。接下来&#xff0c;我…

记录让cursor帮我给ruoyi-vue后台管理项目整合mybatis-plus

自己整合过程中会出现 work.web.exception.GlobalExceptionHandler :100 | 请求地址/admin/device/install/detail/1,发生未知异常. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.fire.mapper.DeviceInstallMapper.selectById at o…

HUMANITY’S LAST EXAM (HLE) 综述:人工智能领域的“最终考试”

论文地址&#xff1a;Humanity’s Last Exam 1. 背景与动机 随着大型语言模型&#xff08;LLMs&#xff09;能力的飞速发展&#xff0c;其在数学、编程、生物等领域的任务表现已超越人类。为了系统地衡量这些能力&#xff0c;LLMs 需要接受基准测试&#xff08;Benchmarks&…

利用大型语言模型在量化投资中实现自动化策略

“Automate Strategy Finding with LLM in Quant investment” 论文地址&#xff1a;https://arxiv.org/pdf/2409.06289 摘要 这个新提出的量化股票投资框架&#xff0c;利用大型语言模型&#xff08;LLMs&#xff09;与多智能体系统相结合的方法&#xff0c;通过LLMs从包括数…

OpenCV:在图像中添加高斯噪声、胡椒噪声

目录 在图像中添加高斯噪声 高斯噪声的特性 添加高斯噪声的实现 给图像添加胡椒噪声 实现胡椒噪声的步骤 相关阅读 OpenCV&#xff1a;图像处理中的低通滤波-CSDN博客 OpenCV&#xff1a;高通滤波之索贝尔、沙尔和拉普拉斯-CSDN博客 OpenCV&#xff1a;图像滤波、卷积与…

大数据学习(40)- Flink执行流

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博主哦&#x1f91…

Prometheus+Grafana监控minio对象存储

1. 安装 MinIO 步骤 1&#xff1a;下载 MinIO 二进制文件 wget https://dl.min.io/server/minio/release/linux-amd64/miniochmod x miniosudo mv minio /usr/local/bin/ 步骤 2&#xff1a;创建数据目录 sudo mkdir -p /data/miniosudo chown -R $USER:$USER /data/minio …

2025数学建模美赛|F题成品论文

国家安全政策与网络安全 摘要 随着互联网技术的迅猛发展&#xff0c;网络犯罪问题已成为全球网络安全中的重要研究课题&#xff0c;且网络犯罪的形式和影响日益复杂和严重。本文针对网络犯罪中的问题&#xff0c;基于多元回归分析和差异中的差异&#xff08;DiD&#xff09;思…

期权帮|如何利用股指期货进行对冲套利?

锦鲤三三每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 如何利用股指期货进行对冲套利&#xff1f; 对冲就是通过股指期货来平衡投资组合的风险。它分为正向与反向两种策略&#xff1a; &#xff08;1&#xff09;正向对冲&#xff…

QT 中 UDP 的使用

目录 一、UDP 简介 二、QT 中 UDP 编程的基本步骤 &#xff08;一&#xff09;包含头文件 &#xff08;二&#xff09;创建 UDP 套接字对象 &#xff08;三&#xff09;绑定端口 &#xff08;四&#xff09;发送数据 &#xff08;五&#xff09;接收数据 三、完整示例代…

Android BitmapShader简洁实现马赛克,Kotlin(二)

Android BitmapShader简洁实现马赛克&#xff0c;Kotlin&#xff08;二&#xff09; 这一篇 Android BitmapShader简洁实现马赛克&#xff0c;Kotlin&#xff08;一&#xff09;-CSDN博客 遗留一个问题&#xff0c;xml定义的MyView为wrap_content的宽高&#xff0c;如果改成其…

分布式光纤应变监测是一种高精度、分布式的监测技术

一、土木工程领域 桥梁结构健康监测 主跨应变监测&#xff1a;在大跨度桥梁的主跨部分&#xff0c;如悬索桥的主缆、斜拉桥的斜拉索和主梁&#xff0c;分布式光纤应变传感器可以沿着这些关键结构部件进行铺设。通过实时监测应变情况&#xff0c;能够精确捕捉到车辆荷载、风荷…

uniapp的插件开发发布指南

Hbuilder创建项目 项目根目录创建uni_modules 开发组件 发布到插件市场 填写发布说明&#xff08;未登录需要登录&#xff09; 点击提交 在终端可以看到 发布成功&#xff01; 插件市场查看

大厂案例——腾讯蓝鲸DevOps类应用的设计与实践

蓝鲸体系架构图 蓝鲸CICD应用功能架构 降低DEVOPS门槛—开发者中心 CICD应用需要的后台服务 系列阅读 12306亿级流量架构分析&#xff08;史上最全&#xff09;实现电商平台从业务到架构的治理体系基于主数据驱动的数据治理什么时候需要分表分库&#xff1f;-CSDN博客

Jetson nano 安装 PCL 指南

本指南帮助 ARM64 架构的 Jetson Nano 安装 PCL&#xff08;点云库&#xff09;。 安装步骤 第一步&#xff1a;安装依赖 在终端中运行以下命令&#xff0c;安装 PCL 所需的依赖&#xff1a; sudo apt-get update sudo apt-get install git build-essential linux-libc-dev s…