尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Item24--若所有参数皆需类型转换,请为此采用 non-member 函数

Item24--若所有参数皆需类型转换,请为此采用 non-member 函数
📅 发布时间:2026/6/19 23:59:49

1. 核心场景:混合算术运算

为了讲解这个条款,我们依然使用经典的 有理数类 (Rational),并希望支持整数隐式转换为有理数(例如 5 变成 5/1)。

前提条件:你的构造函数不能是 explicit 的(允许隐式转换)。

class Rational {
public:// 构造函数不带 explicit,允许 int -> Rational 的隐式转换Rational(int numerator = 0, int denominator = 1); int numerator() const;int denominator() const;
};

我们现在的目标是支持乘法:Rational * int,以及 int * Rational。


2. 错误的尝试:作为 Member Function

按照面向对象的直觉,我们首先把它写成成员函数:

class Rational {
public:...// 成员函数版乘法const Rational operator*(const Rational& rhs) const;
};

测试 Case 1:正常情况

Rational oneHalf(1, 2);
Rational result = oneHalf * oneHalf; // ✅ 没问题

等价于:oneHalf.operator*(oneHalf)。

测试 Case 2:混合运算(对象在左,Int 在右)

result = oneHalf * 2; // ✅ 没问题!

发生了什么?

  1. 编译器看:oneHalf.operator*(2)。
  2. 参数类型不匹配:函数需要 Rational,但你给了 int。
  3. 编译器发现:构造函数 Rational(int) 可以把 2 变成 Rational(2)。
  4. 隐式转换发生:调用成功。

测试 Case 3:混合运算(Int 在左,对象在右)

result = 2 * oneHalf; // ❌ 编译失败!

为什么失败?

  1. 这行代码试图执行:2.operator*(oneHalf)。
  2. 整数 2 是内置类型,它没有成员函数,当然也就没有 operator*。
  3. 编译器不会尝试把左侧的 2 转换成 Rational 来调用成员函数。

核心规则:只有当参数列在参数列表(Parameter List)中时,隐式类型转换才会发生。 对于成员函数,this 指针(即调用者本身,操作符左侧的对象)不是函数参数,所以它绝不会发生隐式转换。


3. 正确的解法:Non-Member Function

为了让乘法交换律成立(即 A * B 和 B * A 都要支持),我们需要让操作符左侧和右侧的变量地位平等,都能够享受“隐式类型转换”的待遇。

这就要求:两个都要是函数的参数。 显然,只有 Non-member function 能做到这一点。

// 定义在类外面
const Rational operator*(const Rational& lhs, const Rational& rhs) {return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}

再次测试 Case 3

result = 2 * oneHalf; // ✅ 现在成功了!

发生了什么?

  1. 编译器寻找 operator*(2, oneHalf)。
  2. 发现我们定义的全局函数接受两个 Rational。
  3. 编译器非常勤快:
    • 把左边的 2 隐式转换为 Rational(2)。
    • 右边已经是 Rational。
  4. 函数调用成功!

4. 这里的 Friend 问题

在 Item 23 中,我们刚学过“尽量不要用 Friend”。那么在 Item 24 中,这个非成员的 operator* 应该是 Friend 吗?

这取决于 Public 接口是否足够。

情况 A:Public 接口足够(推荐)

如果 Rational 类提供了 numerator() 和 denominator() 的 Public 访问函数(如上面的例子),那么 operator* 完全不需要是 Friend。 它可以利用 Public 接口完成任务。符合 Item 23 的精神:Non-member Non-friend。

情况 B:Public 接口不足(不得不 Friend)

如果 Rational 没有公开分母和分子的访问器,或者为了极致的性能(省去函数调用开销,虽然内联能解决),你必须直接访问私有数据 n 和 d。 这时,你不得不把 operator* 声明为 Friend。

总结:Item 24 的核心是“必须是 Non-member”。至于是不是 Friend,看具体情况,能不是就不是。


5. 总结 (Summary)

  1. 问题:如果你希望一个函数的所有参数(尤其是左边的那个)都能支持隐式类型转换。
  2. 限制:Member function 的 this 指针(左侧对象)无法进行隐式转换。
  3. 解决方案:必须将该函数定义为 Non-member function。
  4. 典型场景:算术运算符重载(operator*, operator+ 等)涉及混合运算(int * Object)时。

相关新闻

  • 基于java的SpringBoot/SSM+Vue+uniapp的赛车爱好者交流平台的详细设计和实现(源码+lw+部署文档+讲解等)
  • Item25--考虑写出一个不抛异常的 swap 函数
  • 3562. 折扣价交易股票的最大利润

最新新闻

  • 枚举类三大应用场景 - -z-w-h
  • 如何安装和配置Google Translate Mac客户端:5分钟快速上手教程 [特殊字符]
  • winget只下载不安装
  • express-winston性能优化:减少日志开销的7个最佳实践
  • 2026苏州防水补漏维修团队实测盘点TOP4:苏州业主房屋渗漏修缮靠谱选择 - 宅安选房屋修缮
  • GEO获客优化推广与传统SEO、短视频搜索的差异化体验解析 - 起跑123

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号