为什么有的操作符重载函数只能是成员函数?

  出自于c++ primer 5e的一句话:

赋值(=)、下标([])、调用(())和成员访问箭头(->)运算符必须是成员(函数)。

  为什么?对于赋值运算符来说,我们知道一个c++类,程序员如果没有为其定义了赋值操作符重载函数,编译器也会隐式的定义,这样倘若再定义全局赋值运算符重载函数,将会发生二义性。即使编译器允许这样的定义手法,在调用的时候也编译不过:

cls& operator=(cls& c1, const cls& c2)
{
    //...
    return c1;
}

class cls
{
public:
    int m_a;
    char m_c;

    cls(int a, char c) : m_a(a), m_c(c) {}
};

int main(void)
{
    cls c1(1, 2), c2(3, 4);

    c1 = c2;    //调用的是编译器隐式定义的operator=()还是程序员显示定义的全局的operator=()

    return 0;
}

  操作符重载函数规定是类的成员函数,有一个至关重要的特点:类的this指针会被绑定到运算符的左侧运算对象,成员运算符函数的显示参数比运算符对象总数少一个。也就是说上文提到这些运算符的左操作数必须是该类类型的参数,换句话说,假设c++编译器允许[]操作符重载函数是全局的,那么程序员完全可以写出:

cls& operator[](int dat, cls& c)
{
    //...
    return c;
}

int main(void)
{
    cls c(1, 'h');
    6[c];

    return 0;
}

  因为[]操作符重载函数是全局(友缘)的,也就是没有了该函数的左操作数是this指针的限制,程序员可以任意定义左操作数的类型,类似的,就会出现6=c, 6(c), 6->c的代码,显然这样的代码是错误的。
  不仅如此,假设cls类定义了转换构造函数:

cls::cls(int i);

  那么 operator的函数原型大可以是:

cls& operator[](cls& c1, cls& c2)
{
    //...
    return c1;
}

  看似正确,但是若用户利用转换构造函数的隐式类型转换调用该函数:

int main(void)
{
    cls c(1, 'h');
    6[c];

    return 0;
}

  同样编译通过,显然这还是错误的。因此,c++编译器对这些操作直接视为语法问题。

  另外我们可以推测string类的加号操作符重载函数是有两个版本的。如下正常运行的代码:

std::string s1 = "hello";
const char* s2 = "world";

string s3 = s1 + "world";   
string s4 = "world" + s1;

  代码中的两个加法操作分别执行成员函数的

string& operator+(const string& s);

和友缘全局函数的

string& opreator+(std::string s1, std::string& s2);

  因为假设二者都是调用成员函数的operator+(),那么第2个加法语句等价于

s4 = s2.operator+(s1);

然而s2是const char*类型,根本没有成员函数。

  • 42
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值