原本写这篇主要是想记录一下发现的一个冷知识:C++中运算符重载是作为类对象的成员函数,而C#中是作为类的静态成员函数。因为昨天睡觉的时候我突然想起来,C++中类里面的比较函数一般都要定义为static的,才能传到sort函数里,但是operator重载的运算符本身意义也非常符合属于类本身,而不是单个对象的这种意义,为什么就不是定义成static的呢?查了下发现C#中果然就是需要把类中的运算符重载定义成static的。结果写着写着写多了,只好顺便把C++中运算符重载的东西给总结一下。个人感觉C#的方式更合理直观一点,早就看C++的运算符重载不顺眼了。文章第二部分解释原因
类实例的成员函数,如果一个函数是成员函数,则其必包含一个隐式的this指针传进去;因此如果运算符时一个成员函数,其左侧运算符对象就绑定到隐式的this参数。即相当于运算符左侧的对象,作为调用这个运算符的实例,其this指针也传了进去。
至于第四条是为什么呢,《C++ Primer》(p493)里给的解释是,如果想提供含有类对象的混合表达式,运算符必须定义为非成员的函数。
string s = "world"; string t = s + "abc"; string u = "hi" + s;如果+运算符定义成一个string类的成员函数的话,第三句话会报错,因为”hi”是一个const char*类型的,它根本就没有成员函数。 另外关于双
目和单目运算符重载的区别:
双目运算符重载为类的成员函数时,函数只显式说明一个参数,该形参是运算符的右操作数。前置单目运算符重载为类的成员函数时,不需要显式说明参数,即函数没有形参。后置单目运算符重载为类的成员函数时,函数要带有一个整型形参。对于2这个问题,比如前置的++,–还有表示正负号的+和-都是这种情况。 对于3这个问题,比如后置的++和–
一般重载运算符的时候,尽量保证重载之后的语义跟之前的相接近。比如重载赋值运算符的时候,就需要返回*this的引用,保证连等性质:
a = b = c;我直觉上觉得用static来修饰运算符的重载是一件符合直觉的事情【但是因为static修饰的成员函数,里面是不含有this指针的,所以必须要像友员那样讲两个操作符都作为参数传进去】但是C++为什么不这样做呢,关于这个问题,并没有找到为什么C++不选择那样做,倒是发现C#是这样要求的,在msdn网站上有个人问了为什么C#里面运算符重载必须是static。 Eric Lippert是前C#的首席工程师,他给解释了为什么C#要选择这样做:
他说他们设计语言特性的时候,首先要考虑到的是优点要超过其代价,在C++中不要求static,的代价太过大,有点太过小。比如这样就牺牲了对称性,比如像上面那个例子中的str+”abc”与”abc”+str,如果重载成成员函数就不行了。这样非常反直觉。通过重载成静态函数,这样能够控制传入的两边的参数。在C++中,只能再非指针类型上,定义重载运算符。而C#中还区分了引用类型和值类型。比如C++中一个比较坑的地方在于: string a = "123"; string b = "asd"; a+b = 3;以上的这种写法居然合理的!之前的一篇文章说过这个问题C++中const和引用修饰变量和函数的总结 因为a+b返回的是一个string类型,其是可以直接调用它的成员函数的。虽然C++后来加了限定比如用&&和&来修饰,达到限制调用类型对象左值还是右值引用的目的。 而如果在C#中,就不会有这种情况了,两目运算符的两边都要传进去。
Why are overloaded operators always static in C#?