成员函数可以是虚函数,但非成员函数不能。因此内存卡无法访问函数不正确,如果一个函数必须是动态绑定的,那么它必须是一个虚函数,而虚函数必须是一个类的成员函数。
但如果函数不必是虚拟的,情况就复杂一点。请参见下面的示例。
class Rational {
public:
Rational(int numerator = 0,
int denominator = 1);
int numerator() const;
int denominator() const;
private:
...
};
这是一个无用的课程。(接口确实是最小的,但还远远不够。)因此,我们需要给它添加对加减乘等算术运算的支持,但是到底应该使用成员函数,非成员函数还是非成员函数? – 会员好友功能?
如有疑问,请以面向对象的方式思考!有理数的乘法应该是一个成员函数。
class Rational {
public:
...
const Rational operator*(const Rational& rhs) const;
}
现在很容易将有理数相乘:
Rational one(1, 8);
Rational two(1, 2);
Rational result = one * two; // 运行良好
result = result * one; // 运行良好
但不要满足,还要支持混合类型的运算,比如要能够与int相乘。
result = one* 2; // 运行良好
result = 2 * one; // 出错!为什么?
乘法必须满足交换律。如果你把上面两个例子改写成等价的函数形式,你就会知道为什么:
result = one.operator*(2); // 运行良好,2不是Rational类型,但会发生隐式类型转换
result = 2.operator*(one); // 出错!整数 2 没有相应的类,没有 operator*成员函数。
//编译器还会去搜索非成员的
//operator*函数(全局函数或名字空间中的函数)
result = operator*(2, oneHalf); // 错误!,也找不到
编译器会这样处理它:
const Rational temp(2); // 从 2 产生临时对象
result = one * temp; // 同 one.operator*(temp);
当然,这只有在构造函数没有被显式声明时才有可能,因为显式构造函数不能用于隐式转换。
如果需要,编译器会对每个函数的每个参数执行这种隐式类型转换。但它只转换函数参数表中列出的参数内存卡无法访问函数不正确,而不转换成员函数所在的对象(*this指针对应的对象)。这就是为什么下面的转换失败。
result = 2.operator*(one);
如果您仍想支持混合算术运算,成员函数则不能。唯一的方法是使 operator* 成为非成员函数(允许编译器对所有参数执行隐式类型转换)。
class Rational {
... // contains no operator*
};
// 在全局或某一名字空间声明
const Rational operator*(const Rational& lhs,
const Rational& rhs)
{
return Rational(lhs.numerator() *
rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
Rational one(1, 4);
Rational result;
result = one * 2; // 工作良好
result = 2 * one; // 万岁, 它也工作了!
还有一个问题:operator* 应该成为 Rational 类的朋友吗?
在这种情况下,答案是不必要的。因为 operator* 可以完全通过类的公共接口来实现。上面的代码就是这样做的。尽可能避免使用友元函数。想想现实生活中朋友(朋友)可能会造成一些麻烦的情况,他们可以访问非公共成员。
最后说一下朋友存在的场景——在String类中
如果你想重载 operator>> 和 operator
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 欧资源网