基础语法之七:重载操作符的成员和非成员选择

1、c++ primer :选择成员和非成员实现

  • 赋值(=)、下标([])、调用(())和成员访问箭头(->)等操作符必须定义为成员,将这些操作符定义为非成员函数将在编译时标记为错误。
  • 像赋值一样,复合赋值操作符通常应定义为类的成员,与赋值不同的是,不一定非得这样做,如果定义非成员复合赋值操作符,不会出现编译错误。
  • 改变对象状态或与给定类型紧密联系的其他一些操作符,如自增、自减和解引用,通常就定义为类成员。
  • 对称的操作符,如算术操作符、相等操作符、关系操作符和位操作符,最好定义为普通非成员函数。

但是,问题是为什么?为什么赋值(=)、下标([])、调用(())和成员访问箭头(->)等操作符必须定义为成员?

 

2、具体分析

2.1 调用二义性

c++默认为类生成复制操作符,如果定义赋值操作符重载函数为类的友元【全局函数】,将会引起调用二义性,举个栗子:

class A;

A& operator=(A& a1, const A& a2)
{
    // TODO:
    return a1;
}

class A
{

    // TODO:

};

int main()
{
  
 A a1, a2;

    a2 = a1;    //which operator= is called?

    return 0;
}

2.2 操作语法错误

以[]操作符举例:

A& operator[](int b, A& a)
{
    //...
    return a;
}

int main(void)
{
    A a;
    3[a];

    return 0;
}

同理:2=a, 6(c), 7->c 之类的代码,显然这些代码是语法错误的,原因在于当作为非成员时,函数第一个参数不在约束为this所指向的对象,所以这些定义完全有可能发生;

 

此外,如果A类定义了转换构造函数:

A::A(int i);

此时定义operator[]:

A& operator[](A& a, int b)
{
    //...
    return a;
}

int main(void)
{
    3[2];     // 使用了转换构造函数 3-> class A type

    return 0;
}

 

2.3 string类型的 operator+

另外我们可以推测string类的加号操作符重载函数是有两个版本的。

  • 成员函数:string& operator+(const string& s);
  • 友缘全局函数:string& opreator+(std::string s1, std::string& s2);

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

string s3 = s1 + "world";        // call member func
string s4 = "world" + s1;
       // call friend func

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

s4 = s2.operator+(s1);

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

猜你喜欢

转载自www.cnblogs.com/wnwin/p/9595776.html