重载的运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成。和其他函数一样,重载的运算符也包含返回类型、参数列表以及函数体。
对于一个运算符函数来说,它或者是类的成员,或者至少含有一个类类型的参数
当一个重载的运算符是成员函数时,this绑定到左侧运算对象。成员运算符函数的(显式)参数数量比与运算对象的数量少一个
当我们定义重载的运算符时,必须首先决定是将其声明为类的成员函数还是声明一个普通的非成员函数。在某些时候我们别无选择,因为有的运算符作为普通函数比作为成员更好,有下面原则来选择:
当我们把运算符定义成成员函数时,它的左侧运算对象必须是运算符所属类的一个对象,例如:
string s = "world";
string t = s + "!"; //正确
string u = "hi" + s; //错误
使用下面声明的类来解决各种运算符重载
class Test {
public:
friend ostream& operator<<(ostream&, const Test&);
friend istream& operator>>(istream&, Test&);
friend Test operator+(const Test&, const Test&);
Test& operator+=(const Test&);
friend bool operator==(const Test&, const Test&);
friend bool operator!=(const Test&, const Test&);
int& operator[](int n) { return vec[n]; }
const int& operator[](int n) const { return vec[n]; }
Test(){}
Test(int _data1,int _data2) : data1(_data1),data2(_data2) {}
~Test() {}
private:
vector<int> vec;
int data1;
double data2;
};
一般声明为类的友元函数,便于访问类的私有函数
ostream& operator<<(ostream& os, const Test& test) {
os << test.data1 << " " << test.data2;
return os;
}
第一个参数是ostream的非常量引用,非常量是因为向流写入会改变状态,引用是IO对象不允许拷贝,第二个参数是要输出类的对象的常引用。
istream& operator>>(istream& is, Test& test) {
is >> test.data1 >> test.data2;
if (is) {
//...
}
else {
test = Test();
}
return is;
}
重载输入运算符必须处理输入可能失败的情况,而输出运算符不需要
输入时的错误:
Test& Test::operator+=(const Test& test) {
data1 += test.data1;
data2 += test.data2;
return *this;
}
通常情况下,我们把算术和关系运算符定义成非成员函数以允许对左侧或右侧的运算对象进行转换,因为这些运算符一般不需要改变运算对象的状态,所以形参都是常量的引用。
Test operator+(const Test& test1, const Test& test2) {
Test newTest = test1;
newTest += test2;
return newTest;
}
bool operator==(const Test& test1, const Test& test2) {
return test1.data1 == test2.data1 && test1.data1 == test2.data2;
}
bool operator!=(const Test& test1, const Test& test2) {
return !(test1 == test2);
}
int& operator[](int n) { return vec[n]; }
const int& operator[](int n) const { return vec[n]; }
//前置
Test& Test::operator++() {
++data1;
++data2;
return *this;
}
Test& Test::operator--() {
--data1;
--data2;
return *this;
}
//后置
Test Test::operator++(int) {
Test test = *this;
++*this;
return test;
}
Test Test::operator--(int) {
Test test = *this;
--* this;
return test;
}
operator type() const;
举个例子:
class SmallInt {
public:
SmallInt(int i = 0): val (i){
if(i<011i>255)
throw std: :out_ of_ range ("Bad SmallInt value") ;
}
operator int() const { return val; }
private :
std: :size_ t val;
};
int main(){
SmallInt si;
int tmp = si+3; //首先将si隐式转换成int,然后执行整数的加法
}
在实践中,类很少提供类型转换运算符。在大多数情况下,如果类型转换自动发生,用户可能会感觉比较以外,而不是感觉受到了帮助。
所以C++新标准引入了显式的类型转换运算符
class SmallInt{
public:
explicit operator int() const {return val;}
}
int main(){
SmallInt si;
int tmp = static_cast<int>si+3;
}
该规定存在一个例外,即如果表达式被用作条件,则编译器会将显式的类型转换自动应用于它。换句话说,当表达式出现在下列位置时,显式的类型转换将被隐式地执行: