基本概念
重载的运算符是具有特殊名字的函数:它们的名字由关键字 operator 和其后要定义的运算符号共同组成,如果一个运算符是成员函数,则它的第一个运算对象绑定到隐式的 this 指针上,因此成员运算符函数的显式参数数量比运算对象总数少一个。
当把运算符定义成成员函数时,它的左侧运算对象必须是运算符所属类的一个对象,如果我们像提供含有类对象的混合类型表达式(类似 int + double),则运算符必须定义成非成员函数。
输入和输出运算符
输入输出运算符必须是非成员函数
ostream &operator<<(ostream &os, const Sales_data &item){os << item.isbn() << " " << item.units_sold << " "<< item.revenue << " " << item.avg_price();return os;}
算术和关系运算符
因为这些运算符一般不需要改变运算对象的形态,所以形参都是常量的引用。
Sales_dataoperator+(const Sales_data &lhs, const Sales_data &rhs){Sales_data sum = lhs;sum += rhs;return sum;}
赋值运算符
与拷贝赋值及移动赋值运算符一样,其他重载的赋值运算符也必须先释放当前内存空间,再创建一片新空间
class StrVec {public:StrVec &operator=(std::initializer_list<std::string>);};StrVec &StrVec::operator=(initializer_list<string> il){// alloc_n_copy 分配内存空间并从给定范围内拷贝元素auto data = alloc_n_copy(il.begin(), il.end());free();elements = data.first;first_tree = cap = data.second;return *this;}
递增和递减运算符
为了与内置版本保持一致,后置运算符应该返回对象的原值,返回的形式是一个值而非引用
class StrBlobPtr {public:StrBlobPtr& operator++(); // 前置运算符StrBlobPtr operator++(int); // 后置运算符};StrBlobPtr& StrBlobPtr::operator++(){// 如果指针已经指向了容器的尾后位置,则无法递增它check(curr, "increment past end of StrBlobPtr");++curr;return *this;}StrBlobPtr StrBlobPtr::operator++(int){// 此处无须检查有效性,调用前置递增运算时才需要检查StrBlobPtr ret = *this;++*this;return ret;}
成员访问运算符
class StrBlobPtr {public:std::string& operator*() const {auto p = check(curr, "dereference past end");return (*p)[curr]; // (*p) 是对象所指的 vector}std::string* operator->() const {// 将实际工作委托给解引用运算符return & this->operator*();}};
我们能令 operator* 完成任何我们指定的操作,但箭头运算符永远不能丢掉成员访问这个最基本的含义。
对于形如 point -> mem 的表达式,point 必须是指向类对象的指针或者是一个重载了 operator-> 的类的对象。根据 point 类型的不同,point -> mem 分别等价于
(*point).mem; // point 是一个内置的指针类型
point.operator()->mem; // point 是类的一个对象
函数调用运算符
如果类重载了函数调用运算符,则我们可以像使用函数一样使用使用该类的对象。
struct absInt {
int operator()(int val) const {
return val < 0 ? -val : val;
}
};
