题外话,贴个白噪音网站 Rainy Mood ,敲代码的时候可以听,就像不存在一样
言归正传
在C++复制控制那篇帖子里面,有提到操作符的功能实际上都是被定义出来的。--这一点其实可以推广到其他的语言,只不过其他语言禁止了自定义操作符。
先说个总结认识:操作符本质上是函数,只不过不同于普通函数,标准里单独规定了怎么写怎么调用它。
前提:
语言底层实现了内置类型的操作符定义,并且,不允许重新自定义内置类型的操作符。
为了保证内置类型的操作符不被重载,编译器对操作符函数做出了限制---这个稍后再说。
规定一:
操作符函数都是以operator再加上操作符作为函数名的,如operator+、operator=等等。
只要正确的定义(重载)了操作符函数,那么相应类型去调用操作符时,本质上就是调用这个操作符函数。--例如复制控制那篇里提到过的赋值操作符重载。
如:
#include <iostream> #include <string> #include <sstream> using namespace std; class Person{ private: string name; int age; public: Person(string _name="anonymous", int _age=18):name(_name),age(_age){} //带默认实参的构造函数 Person operator+(const Person &person_b){ Person person; //default person.name = name + person_b.name; // person.age = age + person_b.age; return person; } string toString(){ // 模仿Java的toString()。实际上不必这样,见<<重载。 ostringstream out; out<<"name=["<<name<<"], age=["<<age<<"]"; return out.str(); } }; int main(){ Person p1; Person p2; Person p3,p4; p3=p1+p2; // operator + p4=p1.operator+(p2); // cout<<"p3:"<<p3.toString()<<endl; cout<<"p4:"<<p4.toString()<<endl; return 0; }
上面,p1+p2 和p1.operator+(p2) 是完全一致的,也就是说编译器规定了遇到+就会去调用operator+() 。其他的操作符同理。
不想打字了,直接上代码吧。
下面的代码示例了类型转换、调用操作符重载、io流重载。
有一点需要分清楚:io流重载是输出到流或者从流输入用的,而类型转换却不是。
这里极其容易将输出流误认为转换成string等---但这不是一回事!!!
#include <iostream> #include <string> #include <sstream> using namespace std; class A{ private: int num; public: A(int _num=0):num(_num){ cout<<"构造函数"<<endl; } //输出函数 virtual void print()const{ cout<<num<<endl; } //转成string virtual operator string() const{ cout<<"operator string() called"<<endl; ostringstream out; out<<num; return out.str(); } operator int() const{ cout<<"operator int() called"<<endl; return num; } // ostream &operator<<(ostream &in) const{ //不能这样写,因为默认第一个操作数是this?会导致a<<cout<<endl;这样的写法 // cout<<"operator<< called"<<endl; // return in<<num; // } //调用操作符() 重载--这里用于设置新值 virtual void operator() (const int &_num){ cout<<"调用操作符() 重载"<<endl; num=_num; } public: friend ostream &operator<<(ostream &in, const A &a); // friend ostream &operator<<(const A &a ,ostream &in); //会导致a<<cout<<endl;这样的写法 }; // 为了跟默认的io操作一致,要求形参顺序必须这样!否则就是下面那样,会导致a<<cout<<endl;这样的写法 ostream &operator<<(ostream &in, const A &a) { cout<<"operator<< called"<<endl; return in<<a.num; } // 会导致a<<cout<<endl;这样的写法 // ostream &operator<<( const A &a,ostream &in) { // cout<<"operator<< called"<<endl; // return in<<a.num; // } int main(int argc, char const *argv[]) { A a; a(5);//函数对象 cout << a << endl; //奇怪,为什么之前就可以?operator_overload2.cpp --因为默认没有转成string,而是转成了int string s(a); cout<<s<<endl; cout<<"---"<<endl; cout<<a<<endl; // a<<cout<<endl; // (a<<cout)返回cout, 再cout<<endl;卧槽 return 0; }