考虑一个简单的向量类实现:
#include <algorithm>
class Vector {
public:
Vector(int _elementsCount)
: elementsCount(_elementsCount)
, elements(new float[_elementsCount])
{}
~Vector() {
delete[] elements;
}
Vector(const Vector& rhs) {
elementsCount = rhs.size();
elements = new float[elementsCount];
for (int i = 0; i < elementsCount; ++i)
(*this)[i] = rhs[i];
}
float& operator [](int i) {
return elements[i];
}
float operator [](int i) const {
return const_cast<Vector&>(*this)[i];
}
int size() const {
return elementsCount;
}
/*// Dot product
float operator *(const Vector& v) {
float res = 0;
for (int i = 0; i < size(); ++i)
res += (*this)[i] * v[i];
return res;
}*/
private:
int elementsCount;
float* elements;
};
// Multiplication by a scalar
Vector operator *(const Vector& v, float k) {
Vector res(v.size());
for (int i = 0; i < v.size(); ++i)
res[i] = v[i] * k;
return res;
}
// Dot product
float operator *(const Vector& v1, const Vector& v2) {
float res = 0;
for (int i = 0; i < std::min(v1.size(), v2.size()); ++i)
res += v1[i] * v2[i];
return res;
}
void main()
{
Vector v(2);
v * 3; // ambiguous
}这段代码编译。但是,如果取消类中的*操作符实现,并注释它的全局实现(点积函数),则会出现一个错误“向量::运算符*:2重载有类似的转换”,因为其中有一个歧义:是用标量调用乘法,还是将3解释为参数化构造函数的参数,并调用点积。这说得通。但我不明白将*操作符声明为成员函数或全局函数有什么区别。我认为在上面的例子中它们应该是一样的,但事实并非如此。
补充说,我最感兴趣的不是如何避免歧义,而是为什么在一种情况下(当*被声明为成员时)而在另一种情况下没有歧义(当*被声明为全局函数时)。
发布于 2021-11-25 00:00:17
您需要使构造函数explicit
explicit Vector(int _elementsCount) { ... }造成这种模糊性的原因是编译器无法决定是隐式地将int值转换为Vector并调用Vector::operator*,还是隐式地将int值转换为float并使用operator*(const Vector&, float)。
通过使用explicit,这种转换是被禁止的,如果您希望"3“成为一个Vector,则必须使用Vector(3)。
另外,您应该使操作符const,因为它不修改对象。使之成为const还将允许它与const Vector一起使用
float operator *(const Vector& v) const { ... }请注意,这仍将与您的其他过载冲突:
float operator *(const Vector& v1, const Vector& v2) 没有理由两者兼得。选择成员函数或全局函数,然后删除另一个函数。
https://stackoverflow.com/questions/70104318
复制相似问题