一个例子
假设String类中定义了两个重载的等于操作符
bool operator==(const String &) const;
bool operator==(const char *) const;
实际写代码时,我们会发现
String flower="tulip";
"lily"=flower;
会导致编译错误,原因就在于
只有在左操作数是该类类型的对象的时候,才会考虑使用作为类成员的重载操作符。
如果左操作数不是类类型,那么编译器会试图找到一个内置操作符,他可以有一个C风格字符串的左操作数和一个String类型的右操作数。但事实上并不存在这样的操作符,所以引发 编译错误。
一个解决方法是,我们构造一个类构造函数,将左操作数转换成定义该操作符类的类类型,令编译器在编译的时候将左操作数自动转换为类类型
但是,如果这样的话,那么编译必须搜查所有的类定义,找到所有能把做操作数转换为类类型的构造函数,然后为每一个类类型找到相关的重载等于操作符,看是否有一个能执行等于操作。接着,编译器还需要判断哪一个"构造函数和等于操作符"的组合对于右操作数是最佳匹配。
如果要求编译器这样做的话,那么将会收到很好的事倍功半的效果。
因此,我们不要求编译器这么做,我们只要求编译器考虑左操作数的类中定义的成员重载操作符(也包括其基类)
当然我们也可以把重载操作符声明为非类成员
bool operator==(const String & , const String &);
cool operator==(const String & ,const char *);
我们注意到全局重载操作符比成员重载操作符多了一个参数。
当一个重载操作符是一个名字空间的函数时,对于操作符的第一个和第二个参数,即操作符的左右两个操作数都会考虑转换。
我们可否提供更全面的重载操作符,比如
bool operator==(const char *,const String &);
bool operator==(const String &,const char *);
我们当然可以这样做,但显然这并不是必须的。
这将取决于从 C风格字符串到String 的类型的转换开销即它会取决于应用程序中调用String构造函数引起的额外开销。如果我们预料到会频繁的使用等于操作符来比较C风格字符串和String型的对象,则提供所有这三个名字空间全局操作符就算是好主意。
最后,关于何时把一个操作符声明为类成员或者是名字空间成员。有这么亮点硬性的要求。
1、如果一个重载操作符是类成员,那么只有当跟他一起被使用的左操作数是该类的对象时,他才会被调用。如果该操作符的做操作数必须是其他的类型,那么重载操作符必须是名字空间成员。
2、C++要求,赋值,下标,调用,和成员访问箭头 操作符必须被定义为类成员操作符。否则,编译错误。