为什么C++运算符重载需要"having at least one parameter of class type"?

why C++ operator overloading requires "having at least one parameter of class type"?

本文关键字:parameter one of class type least having 运算符 C++ 重载 为什么      更新时间:2023-10-16

《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转换为两个字符串?毕竟,在两个std::字符串上有一个重载的"+"。string operator+ (const string& lhs, const string& rhs);

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

是的,它是。为什么?嗯,主要原因可能是因为重新定义标准类型的常用操作符被视为混淆。想象重载operator+(int,int)operator+(int,char*)。这将改变现有代码的含义!

你可以争辩说,在标准类型之间有没有定义的操作符,所以你可以安全地覆盖它们,例如operator*(char*,int),但这通常被认为是相当无用的。

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

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

好吧,首先,std::operator+(const std::string&, const std::string&)namespace std;中,所以默认情况下不会找到它。

你可以尝试显式调用操作符:std::operator+("hello", "world"),但是,唉,有太多的operator+()重载,其中许多是模板,调用是二义性的。

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

正如Bjarne在Design and Evolution中所说,我们的目标是使扩展语言变得容易,而不是改变语言。如果您只允许重载内置类型,那么您将改变语言,并且允许这样做违背了设计目标。(例如,它会鼓励形成互不相容的方言,从而使社区破裂。)

这个限制是语言规范的一部分吗?如果是的话,为什么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程序的行为。语言不应该让你做这种滥用。