Effective C++之条款23、24

条款23:宁以non-member、non-friend替换member函数

    假设有这样一个类如下所示:

class WebBrowser {
	public:
	...
	void clearCache();
	void clearHistory();
	void removeCookies();
};

    许多用户会想一整个执行所有这些动作,因此WebBrowser也提供这样一个函数:

class WebBrowser {
public:
	...
	void clearEverything() {
		clerCache();
		clearHistory();
		removeCookies();
	}
};

    当然,这一技能也可以由一个non-member函数调用适当的member函数而提供出来:

void clearBrowser(WebBrowser& wb) {
	wb.clearCache();
	wb.clearHistory();
	wb.removeCookie();
}

    那么哪一个比较好呢?面向对象守则要求,数据以及操作数据的那些函数应该被捆绑在一起,这意味着建议member函数是较好的选择。面向对象守则要求数据应该尽可能被封装,然而与直观相反的,member函数clearEverything带来的封装性比non-member函数clearBrowser低。

    现在考虑对象内的数据。愈少代码可以看到数据,愈多的数据可被封装,而我们也就愈能自由地改变对象数据,例如改变成员变量的数量、类型等等。愈多函数可访问数据,数据的封装性就愈低。

    一个class的non-member函数可能是另一个class的member函数。在C++中,比较自然的做法是让clearBrowser成为一个non-member函数并且位于WebBrowser所在的同一个namespace(命名空间)内:

namespace WebBrowserStuff {
	class WebBrowser {...};
	void clearBrowser(WebBrowser& wb);
	...
};


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

    假设你设计一个class用来表现有理数,允许整数“隐式转换”为有理数似乎颇为合理。假设你有这样的Ratinal class:

class Rational {
public:
	Rational(int numrator = 0, in denominator = 1);
	int numerator() const;
	int denominator() const;
	const Rational operator* (const Rational& rhs) const;
private:
	...
};

    这样的设计使你能够将两个有理数相乘:

Rational oneEight(1, 8);
Rational oneHalf(1, 2);
Rational result = oneHalf * oneEight;
result = result * oneEight;

    然而当你尝试混合式运算,你会发现只有一半行得通:

result = oneHalf * 2;   //OK
result = 2 * oneHalf;   //fault

    当你以对应的函数形式重写上述两个式子,问题所在便一目了然:

result = oneHalf.operator*(2);   //ok,2被隐式转换为Rational对象
result = 2.operator*(oneHalf);   //fault,2不在参数列,不能作隐式转换

    由于整数2并没有相应的class,也就没有operator成员函数。编译器也会尝试寻找可被以下方式调用的non-member operator(也就是在命名空间内或在global作用域内):

result = operator*(2, oneHalf);

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

    要想让上述语句都能通过编译,则只需让operator*成为一个non-member函数,便允许编译器在每一个实参身上执行隐式类型转换:

class Rational {
	...
};
const Rational operator*(const Rational& lhs, const Rational& rhs) {
	return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
Rational oneFourth;
result = 2 * oneFourth;    //OK

请记住

  • 如果你需要为某个函数的所有参数(包括this指针所指的那个参数)进行类型转换,那么这个函数必须是个non-member。
发布了33 篇原创文章 · 获赞 6 · 访问量 569

猜你喜欢

转载自blog.csdn.net/weixin_43519984/article/details/102579687