当前位置: 首页 > article >正文

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/2
    Rational<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/2
    Rational<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; // OK
    Rational<int> r3 = 2 + r1; // OK
    std::cout << "Success!" << std::endl;
    return 0;
}

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

4、总结

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

http://www.kler.cn/a/518247.html

相关文章:

  • LVGL+FreeRTOS实战项目:智能健康助手(xgzp6847a篇)
  • 【算法工程】VS Code问题解决:Failed to parse remote port from server output
  • Java多线程的面试面试题及答案解析
  • Golang之Context详解
  • 【pytorch 】miniconda python3.11 环境安装pytorch
  • 无公网IP 外网访问媒体服务器 Emby
  • GS论文阅读--GeoTexDensifier
  • 如何实现分页相关功能
  • 比简单工厂更好的 - 工厂方法模式(Factory Method Pattern)
  • Lambda 表达式
  • 笔记《Effective Java》01: 创建和销毁对象
  • 软件测试丨消息管道(Kafka)测试体系
  • 电路研究9.2.1——合宙Air780EP音频的AT控制指令
  • 【工程篇】01:GPU可用测试代码
  • python学opencv|读取图像(四十四)原理探究:bitwise_and()函数实现图像按位与运算
  • UGUI判断点击坐标是否在UI内部,以及子UI内部
  • 运行虚幻引擎UE设置Visual Studio
  • spark sql中对array数组类型操作函数列表
  • android studio搭建NDK环境,使用JNI (Java 调 C) 二 通过CMake
  • Couchbase UI: Server