Effective C++:条款24:若所有参数皆需类型转换,请为此采用non-member函数

(一)

假设一个class用来表现有理数,允许整数“隐式转换为”有理数似乎很合理。

class Rational{
public:
    Rational(int numerator = 0, int denominator = 1); //刻意不为explicit;允许int-to-Rational隐式转换
    int numerator()const;
    int denominator()const;
};

在支持算术运算符时考虑该由member函数、还是non-member函数来实现:

(1)成员函数的写法:

class Rational{
public:
    const Rational operator*(const Rational& rhs) const;
};

Rational oneEight(1,8);
Rational onehalf(1,2);
Rational result = oneHalf * oneEight;   //nice
result = result * oneEight;   //ok

但是你希望支持混合运算:

result = oneHalf * 2;   //ok 2发生了隐式类型转换。
result = 2 * oneHalf;   //wrong !!!

编译器将上述语句转换为以下语句:

result = oneHalf.operator*(2);   //ok
result = 2.operator*(oneHalf);   //wrong!

oneHalf是一个含operator*函数的class的一个对象。但是2却没有相应的class,编译器会尝试寻找可被以下这般调用的non-member operator*(也就是在命名空间内 或 global作用域内):

result = operator*(2, oneHalf);//wrong!

本例不存在这样一个接受int和Rational作为参数的non-member operator* 因此查找失败。

只有当参数被列于参数列(parameter
list)内,这个参数才是隐式类型转换的合格参与者。地位相当于“被调用之成员函数所隶属的那个对象”——即this对象的那个隐喻参数,绝不是隐式转换的合格参与者。

(二)解决这种问题的方法:

为了支持混合运算。让operator* 成为一个non-member函数,便允许编译器在每一个实参身上执行隐式类型转换:

const Rational operator*(const Rational& lhs, const Rational& rhs)
{
    return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}

result = 2 * oneHalf;//ok!终于编译通过了!

operator*是否要成为Rational的friend函数呢?答案是否定的,因为operator*完全籍由Rational的public接口完成任务;

无论何时如果你可以避免friend函数就该避免。

请记住:

如果你需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member。

Effective C++:条款24:若所有参数皆需类型转换,请为此采用non-member函数

时间: 2024-10-29 10:48:06

Effective C++:条款24:若所有参数皆需类型转换,请为此采用non-member函数的相关文章

Effective C++ 条款24 若所有参数皆需类型转换,请为此采用non-member函数

1. 通常,将只接受拷贝构造函数声明为explict是一个不错的主意,因为这可以避免自动的隐式类型转换所带来的错误,但有些情况下,使类支持隐式类型转换是可行的,例如自定义的数值类型: class Rational{ public: Rational(int numerator=0,int denominator=1); int numerator()const; int denominator()const; private: int numerator; int denominator; }

[Effective C++ --024]若所有参数皆需类型转换,请为此采用non-member函数

引言 假设我们有这样的类: 1 class A{ 2 public: 3 A(int num = 0, int den = 1) {}; 4 int num() const; 5 int den() const; 6 const A operator* (const A& rhs) const; 7 }; 在做乘法时,我们可以采用以下的操作: 1 A a0(1, 2); 2 A a1(1, 3); 3 4 A match = a0 * a1; // 同类型相乘 5 match = match *

读书笔记_Effective_C++_条款二十四: 若所有参数皆需类型转换,请为此采用non-member函数

class A { private: int a; public: A(int x) :a(x){} A operator*(const A& x) { return A(a*x.a); } }; int main() { A a(2); A b = a*a;//没有问题 A b = a * 2;//由于构造函数没有explicit,这里隐式转换了,也没有问题 A b = 2 * a;//出问题了 } 老师讲过,一种是类的member函数,一种是non-member函数, 但我们为了封装性,尽量

Effective C++ 条款24

若全部參数皆需类型转换,请为此採用non-member函数 我们直奔主题 假设你定义一个有理数类例如以下 class Rational{ public: Rational(int numerator=0, int denominator=1);//非explicit.同意隐式转换 const Rational operator*(const Rational& rhs); ....................... }; result=oneHalf*2;//正确.相当于oneHalf.op

Effective C++ 条款九、十 绝不在构造和析构过程中调用virtual函数|令operator=返回一个reference to *this

  1.当在一个子类当中调用构造函数,其父类构造函数肯定先被调用.如果此时父类构造函数中有一个virtual函数,子类当中也有,肯定执行父类当中的virtual函数,而此时子类当中的成员变量并未被初始化,所以无法调用子类与之对应的函数.即为指向虚函数表的指针vptr没被初始化又怎么去调用派生类的virtual函数呢?析构函数也相同,派生类先于基类被析构,又如何去找派生类相应的虚函数? 2.做法:将子类的某个函数改为non-virtual,然后在子类构造函数中传递参数给父类函数.然后父类的构造函数

Effective C++ 条款44 将与参数无关的代码抽离template

1. template是节省时间和避免代码重复的有效方法,而且在将类模板(class template)具现化时,编译器只具现化那些被用到的成员函数,这更加节省了空间. 2. 正如两个函数存在代码重复时,倾向于把重复的代码抽出独立形成一个函数,然后让之前的函数调用这个函数,函数模板也可以这样,甚至类模板也可以采用相同的思想,例如,对于以下用于操作方矩阵的类模板: template<typename T,std::size_t n> //n是非类型参数 class SquareMatrix{ p

Effective C++ 条款总结

自己在看这本书的时候,回去翻看目录的时候,有些规则会被遗忘,因此做个简单的小总结供自己和其他人参考,没读过的还是要先去读一遍的 一.让自己习惯C++ 1.视C++为一个语言联邦 C++是一种包含许多特性的语言,因而不要把它视为一个单一语言.理解C++至少需要学习一下4个部分: ①C语言.C++仍以C为基础 ②objected-oriented C++.面向对象编程,类.封装.继承.多态 ③template C++.C++泛型编程.模板元编程的基础 ④STL.容器.迭代器.算法 2.尽量使用con

《Effective C++》学习笔记——条款24

***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************** 四.Designs and Declarations Rule 24:Declare non-member functions when type conversions should apply to all parameters 规则 24:若所有参数皆需类

Effective C++笔记_条款46 需要类型转换时请为模板定义非成员函数

看这个章节的时候又跑回去看了一下 条款 24,本章的例子就是基于下面这个例子而来的.在 item 24 中,支持混合运算的示例代码如下: 1 class Rational { 2 public: 3 Rational(int numerator = 0, int denominator = 1); 4 int mumerator() const; 5 int denominator() const; 6 private: 7 int numerator; 8 int denominator; 9