我对c ++运算符有疑问,希望在这里找到答案。 问题的简短版本在标题中,但是如果我真正要问的是任何疑问,这里是长版本。
c ++运算符可以重载,因此可以编写如下内容:
MyClass a(1), b(2);
Myclass c = a + b;
据我了解,典型的实现方式如下:
class MyClass
{
private:
int val;
public:
explicit MyClass(int _val);
MyClass operator+(MyClass const& other) const;
MyClass operator+(int i) const;
};
在这种情况下,它还包含类型为int
的重载,这使得可以编写如下内容:
MyClass a(1);
Myclass b = a + 2;
但不是这样:
MyClass a(1);
Myclass b = 2 + a;
因为这就像调用2.operator+(a)
,而2
不是对象。由于程序员希望以一种可能的方式重载运算符,因此有另一种实现它们的方式,如下所示:
class MyClass
{
private:
int val;
public:
explicit MyClass(int _val);
friend MyClass operator+(MyClass const& lhs, MyClass const& rhs);
friend MyClass operator+(int lhs, MyClass const& rhs);
friend MyClass operator+(MyClass const& lhs, int rhs);
};
允许所有三种类型的添加。
现在,令我困扰的是:如果我们同时实施这两者又该怎么办?编译器如何决定使用成员运算符还是全局运算符?
说句公道话,在任何明智的实现中,调用哪个运算符都无关紧要,它们既不应返回不同的东西,也不应该具有不同的副作用,但是我尝试实现它以查看会发生什么:
class MyClass
{
private:
int val;
public:
explicit MyClass(int _val) : val(_val){}
MyClass operator+(MyClass const& other) const
{
cout << "Call to member operator+ for MyClass+MyClass" << endl;
return MyClass(val + other.val);
}
MyClass operator+(int other) const
{
cout << "Call to member operator+ for MyClass+int" << endl;
return MyClass(val + other);
}
friend MyClass operator+(MyClass const& lhs, MyClass const& rhs)
{
cout << "Call to global operator+ for MyClass+MyClass " << endl;
return MyClass(lhs.val + rhs.val);
}
friend MyClass operator+(int lhs, MyClass const& rhs)
{
cout << "Call to global operator+ for int+MyClass " << endl;
return MyClass(lhs + rhs.val);
}
friend MyClass operator+(MyClass const& lhs, int rhs)
{
cout << "Call to global operator+ for MyClass+int " << endl;
return MyClass(lhs.val + rhs);
}
};
int main() {
MyClass a(1), b(2);
int i(3);
MyClass r_0 = a.operator+(b);
MyClass r_1 = a.operator+(i);
MyClass r_2 = operator+(a,b);
MyClass r_3 = operator+(a,i);
MyClass r_4 = operator+(i,a);
MyClass r_5 = a + b;
MyClass r_6 = a + i;
MyClass r_7 = i + a;
return 0;
}
编译并打印
Call to member operator+ for MyClass+MyClass
Call to member operator+ for MyClass+int
Call to global operator+ for MyClass+MyClass
Call to global operator+ for MyClass+int
Call to global operator+ for int+MyClass
Call to global operator+ for MyClass+MyClass
Call to global operator+ for MyClass+int
Call to global operator+ for int+MyClass
我很容易以为这一切都是合法的,并且全球运营商优先于会员,但是我唯一能在网上找到的东西似乎暗示这些增加是模棱两可的,所以真的是这样吗?还是我只是在这里查看未定义的行为?
答案 0 :(得分:2)
成员函数和非成员函数参与平等权利的重载决议。为了使它们具有可比性,编译器使用隐式对象参数扩展了每个成员函数。 ([over.match.funcs]/p2):
候选函数集可以包含要针对同一参数列表解析的成员和非成员函数。为了使参数列表和参数列表在此异构集合中具有可比性,因此成员函数被视为具有额外的第一个参数,称为隐式对象参数,该参数代表已为其调用成员函数的对象。出于重载解析的目的,静态和非静态成员函数均具有隐式对象参数,而构造函数则没有。
在重载解析过程中,隐含对象参数与其他参数没有区别。但是,隐式对象参数保留其标识,因为无法应用用户定义的转换来实现与之的类型匹配。
鉴于隐式对象参数还继承了非静态成员函数的ref-和cv-qualification,这基本上意味着从编译器的角度来看,成员运算符声明为:
MyClass MyClass::operator+(int) const;
在某种程度上等效于:
MyClass operator+(const MyClass&, int);
唯一区别于常规非成员函数的例外是,第一个参数(隐式对象)不考虑用户定义的转换(这就是1 + a
将切勿使用某些转换构造函数1
将A
转换为A(int)
来调用A::operator+(const A&)
),并且临时实例可以绑定为非常量合格成员函数生成的非常量引用。
成员和全局operator+
在您的代码中含糊不清,因此应产生错误。