为什么C ++运算符重载需要“至少有一个类类型的参数”?

时间:2014-05-06 22:13:08

标签: c++ c++11 operator-overloading

" C ++引言第5版"的第14.1章读,

  

运算符函数必须是类的成员或至少有一个类类型的参数。

例如,string("hello")+"world"编译"hello"+"world"并非如此。当我想在两个C字符串上重载+时。

std::string operator+ (const char* s1, const char* s2)

我收到以下错误。

  

错误:'std :: string operator +(const char *,const char *)'必须有类或枚举类型的参数

我有两个问题。

  1. 这个限制是语言规范的一部分吗?如果是,为什么C ++设计师想要这样做呢?

  2. std::string具有string (const char* s);之类的构造函数,这意味着编译器可以执行从char*string的隐式类类型转换。当我们致电"hello"+"world"时,为什么编译器不会将两个char*" s转换为两个字符串?毕竟,存在重载&# 34 +#34;在两个std :: strings上。 string operator+ (const string& lhs, const string& rhs);

3 个答案:

答案 0 :(得分:6)

正如Bjarne在设计和演变中所说,目标是让扩展语言变得容易,而不是 mutate 。如果您只允许重载内置类型,则会更改语言,并允许这违反了设计目标。 (例如,它会鼓励形成互不相容的方言并破坏社区。)

答案 1 :(得分:4)

  

这个限制是语言规范的一部分吗?如果是,为什么C ++设计师想要这样做呢?

是的,确实如此。引自N3337,§13.5.6[over.oper]:

  

运算符函数应该是非静态成员函数或者是非成员函数,并且至少有一个参数,其类型是类,对类的引用,枚举或对枚举的引用。

关于“为什么”部分,因为删除此要求意味着您可以为已经定义了运算符语义的内置类型重载运算符。那是完全无法忍受的事情。

例如,你认为定义这个有意义吗?

int operator+(int a, int b) { return a - b; }

是否允许更多人在阅读您的代码时推理您的程序,或者只是令人惊讶的事情有效地破坏了您的推理?

如果我们指向游戏,会发生什么?

bool operator==(const char *str1, const char *str2) { 
    return strcmp(str1, str2) == 0;
}

您是否期望operator==现在取消引用记忆?我不会。这令人惊讶。这违反了标准已经说过的关于这些运营商的内容。它破坏了过去25年中每个C程序的表现。这种语言不应该让你做这种滥用。

答案 2 :(得分:4)

  
      
  1. 这个限制是语言规范的一部分吗?
  2.   

是的,确实如此。为什么?好吧,主要原因可能是因为重新定义标准类型的常用运算符被视为混淆。 Imagin重载operator+(int,int)operator+(int,char*)。这将改变现有代码的含义!

您可能会认为标准类型之间存在未定义的运算符,因此您可以安全地覆盖它们,例如operator*(char*,int),但这通常被认为是无用的。

此外,运算符重载必须是全局的(或者在其某些成员的名称空间中(依赖于参数的查找),但是对于标准类型,没有要依赖的命名空间),因此想要覆盖它们的库之间的互操作性会是一场噩梦。

  
      
  1. "hello" + "world":为什么编译器不将两个char *“s转换为两个字符串?
  2.   

嗯,对于一个,std::operator+(const std::string&, const std::string&)位于namespace std;,因此默认情况下无法找到。

你可以尝试明确地调用运算符:std::operator+("hello", "world"),但是,有很多operator+()重载,其中很多是模板,调用是不明确的。

因此,考虑到所有这些因素,我认为合理的要求是至少有一个运营商属于用户定义的类型。考虑一下:解决了全局和名称空间问题,可以使用ADL(实际上它是为此用途而发明的)并且不可能重新定义具有现有含义的运算符(operator,()operator&()除外) ,我想,但是谁想要覆盖这些......)。