
本文共 2826 字,大约阅读时间需要 9 分钟。
C++重载运算符的分析
一、重载运算符
重载运算符,顾名思意,其实就是把一种运算符重新定义成另外一种含义。举一个简单的例子,大家熟知的+这个运算符,应用在数学上,很好理解,但是如果有一个动物类,这个动物类的两从此实例对象相加,是什么意思呢?这就是重载的目的。比如这个动物类中有重量,在动物类中重载这个+运算符,两个实例对象相加就代表着重量的相加,当然,也可以定义成其它,比如每天吃的粮食的重量。
从这个意义上来说,重载运算符给了c++以很大的灵活性,所以做为c++的一项基础的功能,要把它掌握好。
二、重载运算符的种类
1、c++可以重载的运算符
-
-
- / % ^ & | ~ ! = > < += -= = /= %= ^= &=
|= >> << >>= <<= == != >= <= && || ++ – -> , -> [] () new new[]
delete delete []
上面这些运算是都可以重载的。一些细节会在后面展开。
- / % ^ & | ~ ! = > < += -= = /= %= ^= &=
-
2、c++不可以重载的运算符
:: . .* ? : sizeof typeid new delete
static_cast dynamic_cast const_cast reinterpret_cast
3、用户可自定义运算符
这个就比较灵活了,比如:
float operator ""_e(const char*);
3、重载使用的形式
重载运算符可以使用两种形式进行,一种是在类内操作,即重载运算符的函数属于类本身;另外一种是使用友元函数来操作,使用友元的方便之处在于可以访问类的私有变量,恰好有些运算符需要操作类自身的私有属性。
4、使用的一般原则
1、重载一元操作符既可以是成员函数也可以是非成员函数,一元操作符在成员函数无参,否则有一个参数。
2、重载二元操作符同上,但参数相应增加一个。
3、重载=、[]、()、->只能定义为成员函数(这是规定,不要问为什么)。
4、重载->的返回值必须是一个指针或能使用->的对象。
5、重载 ++ 和 – 时带一个 int 参数表示后缀,不带参数表示前缀(区分a++,++a)。
6、除 new 和delete 外,重载的操作符参数中至少要有一个非内部数据类型(非c++自已定义的类型)。
7、x@y决定顺序:x 成员函数;全局函数;X所在名字空间中的函数;Y所在名字空间中的函数;X的友元函数;Y的友元函数。
8、重载的运算符尽量和c++的意义保持一致或者符合正常的思维。
以上这些在c++标准的文档中第十三章中有相关的说明。
5、一些实践的经验
1、一元操作符尽量重载为成员函数。
2、<<和>>两个操作符为和标准库保持一致,尽量重载为非成员函数
3、重载[]这些运算符,应该提供const和非const两个版本。
4、重载不要引起歧义或者多义。
5、不是必须,尽量不要重载new ,delete相关运算符。
三、例子分析
下面分析一个简单的例子,重载了<<运算符:
#include <iostream>using namespace std;class Person {public: Person(int age, int score); //既可以重载为友元,也可以重载为内部成员函数 //不过如果使用ostream的话,就只能使用友元,因为标准库不能修改 friend ostream&operator <<(ostream &os,Person&p); // Person&operator <<(int d);public: //公有的目的是为了验证结果 int m_age; int m_score;};Person::Person(int age, int score){ this->m_age = age; this->m_score = score;}ostream&operator <<(ostream &os, Person&p ){ os << "age " << p.m_age << " score " << p.m_score; return os;}//注释的是处理自己对<<的重载,意思是重载为成员函数也是可以的//Person&Person::operator <<(int os)//{// //os << "age " << p.m_age << " score " << p.m_score;// this->m_age = this->m_score = os;// return *this;//}int main(){ Person p(1, 100); //std:cout << p << std::endl; //Person b = Person(2, 1); std:cout << p << std::endl; //p << 100; //std::cout << p.m_age << p.m_score << std::endl; return 0;}
这里使用了两种形式,既有成员函数也有友元函数,注释里写得也比较清楚,这里再次说明一下,如果想把自己的类与ostream相兼容,互通使用<<或者>>运算符,就只能使用友元函数,否则直接修改标准库的重载,太不划算了。
标准库自带的前后缀示例:
struct X {X& operator++(); // prefix ++aX operator++(int); // postfix a++};struct Y { };Y& operator++(Y&); // prefix ++bY operator++(Y&, int); // postfix b++void f(X a, Y b) {++a; // a.operator++();a++; // a.operator++(0);++b; // operator++(b);b++; // operator++(b, 0);a.operator++(); // explicit call: like ++a;a.operator++(0); // explicit call: like a++;operator++(b); // explicit call: like ++b;operator++(b, 0); // explicit call: like b++;}
如果还是有什么疑问,可以下载c++的标准文档,仔细研究。
四、总结
其实上面的总结还是有些流于形式,只有深入的学习标准文档并加以实践,才能真正的把重载用好。c++的灵活性在这里体现的也比较明显,除了个别强制要求,其它都可以灵活的选择你的重载方式。即使重载的方式反人类的认知方式,c++的编译器也不会认为是错误的。
经验,既是优势,也是累赘。经验需要不断的总结提取否定进步。
发表评论
最新留言
关于作者
