IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 《Effective C++》学习笔记(条款24:若所有参数皆需类型转换,请使用非成员函数) -> 正文阅读

[C++知识库]《Effective C++》学习笔记(条款24:若所有参数皆需类型转换,请使用非成员函数)

最近开始看《Effective C++》,为了方便以后回顾,特意做了笔记。若本人对书中的知识点理解有误的话,望请指正!!!

导读中提过令类支持隐式类型转换是不好的。但是这也是有例外的,最常见的例外就是在建立数值类型时,比如用一个类代表有理数,支持int的隐式转换为有理数是合理的。此外C++自己的内置类型也支持多种隐式转换,例如从int到double,那么我们也可以这样写这个有理数类:

class Rational{
public:
    Rational(int numerator = 0, int denominator = 1);	//门不声明为explicit来允许从int到Rational的隐式转换
    int numerator() const;								//分子的访问函数
    int denominator() const;							//分母的访问函数
  	...
};

既然上述的类时有理数,肯定支持诸如加法、乘法等算术运算,到底用成员函数还是非成员函数来实现呢,还是用非成员非友元函数实现?根据我们的直觉和面向对象的说法,有理数相乘应该在类内实现,即是成员函数。但条款23反直觉地主张,将函数放进相关类内有时会与面向对象守则发生矛盾,但我们先把它放在一旁,将 operator* 写成 Rational 成员函数:

class Rational{
public:
    ...
    //(见条款3为什么要返回const,条款20为什么要使用引用传递,条款21为什么不返回引用)
    const Rational operator*(const Rational& rhs) const;
  	...
};

这个设计可以让两个 Rational 对象相乘:

Rational oneEighth(1,8);
Rational oneHalf(1,2);
Rational result = oneEighth * oneHalf; //编译通过
result = result * oneEighth; //编译通过

当你尝试混合运算时(即 Rational 对象和 int 对象相乘),发现只有一半行得通:

result = oneHalf * 2; //编译通过
result = 2 * oneHalf; //编译错误

乘法应该满足交换律,这样地结果不是我们想要的。

以对应的函数形式重写上述两个式子:

result = oneHalf.operator*(2); //编译通过
result = 2.operator*(oneHalf); //编译错误

问题所在一目了然,oneHalf 是一个内含 operator* 函数的类对象,所以编译器调用该函数。而整数 2 并没有相应的类,也就没有 operator* 成员函数。编译器也会尝试寻找可被以下这般调用的非成员 operator* (也就是在命名空间内或在 global 作用域内):

result = operator*(2, oneHalf);

如果找不到,那么就编译失败。

但我们看第一个成功的语句是不是也有一些疑问? 为什么我们定义的运算符的输入参数是 Rational 对象,但传进去整型 2 也可以编译? 其实这是隐式转换。编译器用我们传进去的 2 隐式地调用了 Rational 的构造函数,因此在编译器眼中是这样的:

const Rational tmp(2);		//用整型 2 构造一个暂时性的Rational对象
result = oneHalf * tmp;	

当然,这是因为声明了 non-explicit 构造函数,编译器才会这样做,如果构造函数声明是 explicit ,以下语句全都编译错误:

result = oneHalf * 2; //编译错误,在explicit 构造函数情况下,无法将2转换为一个Rational对象
result = 2 * oneHalf; //一样的错误,一样的问题

要记住只有在参数表里出现的参数才可以进行隐式转换。第一次调用,整型 2 在 * 的右侧,表明它在参数列表里,即 2 是形参 rhs ,而不再参数列表里的参数,即调用成员函数的对象,即this指向的,是不肯能被隐式转换。第二次调用整型 2 在 * 的左侧,表明是它调用了成员函数,所以编译不通过。

如果你一定要支持混合运算的话,那可以将 operator* 成为一个非成员函数,参与运算的对象都在参数列表内,即都可以进行隐式转换

class Rational{...};//类里不声明operator*函数

//operator*作为非成员函数
const Rational operator*(const Rational& lhs, const Rational& rhs)
{
  return Rational(lhs.numerator() * rhs.numerator(),lhs.denominator() * rhs.denominator());
}

int main()
{
    Rational oneFourth(1,4);
    Rational result;
    result = oneFourth * 2; //编译通过
    result = 2 * oneFourth; //编译通过
    return 0;
}

除了非成员函数,是否可以用友元函数来实现operator*呢?就本例而言答案是否定的。因为我们从 Rational 的 public 接口就已经可以实现想要的功能了,上述代码已表明此种做法。从中得出一个结论:成员函数的反面是非成员函数,不是友元函数。太多C++程序员的人都会有的一个误区: 如果某个函数跟某个类相关,并且不能作为成员函数,那么它就是友元函数。这个例子证明这个想法是不必要的,而且可以避免使用友元函数就不要用

条款25:考虑写出一个不抛异常的swap函数

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-11 12:32:24  更:2021-11-11 12:34:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:40:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码