一、操作符标记和操作符函数
1、双目操作符:L#R
成员函数形式:L.operator# (R) —— 左调右参
全局函数形式:::operator#(L,R) —— 左一右二
2、单目操作符:#O/O#
成员函数形式:O.operator#()
全局函数形式:::operator#(O)
3、三目操作符:不考虑
二、双目操作符
1、+/-/*//
操作数在计算前后不变;表达式的值是右值。
#include <iostream>
using namespace std;
class Complex{
public:
Complex(int r = 0,int i = 0) : m_r(r), m_i(i){}
void print() const{
cout << m_r << "+" << m_i << "i" << endl;
}
//第一个const:返回右值
//第二个const:支持常量型右操作数
//第三个const:支持常量型左操作数
const Complex operator+(const Complex& r) const{
return Complex(m_r + r.m_r, m_i + r.m_i);
}
private:
int m_r;
int m_i;
friend const Complex operator-(const Complex&,const Complex&);//友元
};
const Complex operator-(const Complex& l,const Complex& r){
return Complex(l.m_r - r.m_r,l.m_i - r.m_i);
}
int main(){
Complex c1(1,2);
c1.print();
Complex c2(3,4);
Complex c3 = c1 +c2;//c3 = c1.operator+(c2);
c3.print();//4+6i
c3 = c2 - c1;//c3 = ::operator-(c2,c1);
c3.print();//2+2i
return 0;
}
2、复合赋值运算符:+=/-=/*=…
左变右不变
表达式的值是左值,左操作数的引用。
(a += b) = c;
#include <iostream>
using namespace std;
class Complex{
public:
Complex(int r = 0, int i = 0) : m_r(r), m_i(i){}
void print(void) const{
cout << m_r << '+' << m_i << 'i' << endl;
}
Complex& operator+=(const Complex& r){
m_r += r.m_r;
m_i += r.m_i;
return *this;
}
friend Complex& operator-= (Complex& l, const Complex& r){//友元函数,是个全局函数,不是成员函数,写类里面和外面都行
l.m_r -= r.m_r;
l.m_i -= r.m_i;
return l;
}
private:
int m_r;
int m_i;
};
int main(void){
Complex c1(1,2), c2(3,4);
c1 += c2;//c1.operator+= (c2)
c1.print();//4+6i
Complex c3(5,6);
(c1 += c2) = c3;
c1.print();//5+6i
c1 -= c2;//::operator-= (c1,c2)
c1.print();//2+2i
(c1 -= c2) = c3;
c1.print();
return 0;
}
3、<< / >>
int i = 10;
float f = 1.23;
Complex c (…);
cout << c << i << f << endl;
左操作数ostream/istream类型,不能是常量,不能拷贝。
右操作数自定义类型,对于<<可以是常量,对于>>不能是常量。
表达式的值是左操作数的引用。
::operator<< (cout, c).operator<< (i).operator<< (f).operator<< (endl);
#include <iostream>
using namespace std;
class Complex{
public:
Complex(int r = 0, int i = 0) : m_r(r), m_i(i){}
void print(void) const{
cout << m_r << '+' << m_i << 'i' << endl;
}
friend ostream& operator<< (ostream& os,const Complex& r){
return os << r.m_r << '+' << r.m_i << 'i';
}
friend istream& operator>> (istream& is,Complex& r){
return is >> r.m_r >> r.m_i;
}
private:
int m_r;
int m_i;
};
int main(void){
Complex c1(1,2),c2(3,4);
cout << c1 << endl << c2 << endl;
//::operator<< (::operator << (cout,c1).operator<<(endl),c2).operator<< (endl);
cin >> c1 >> c2;
c1.print();
c2.print();
return 0;
}
三、单目操作符
1、-(取负)/!/~
操作数不变。
表达式的值是右值。
#include <iostream>
using namespace std;
class Complex{
public:
Complex(int r = 0, int i = 0) : m_r(r), m_i(i){}
void print(void) const{
cout << m_r << '+' << m_i << 'i' << endl;
}
const Complex operator-(void) const{
return Complex(-m_r,-m_i);
}
friend const Complex operator~(const Complex& o){
return Complex(o.m_i,o.m_r);
}
private:
int m_r;
int m_i;
};
int main(void){
Complex c1(1,2);
Complex c2 = -c1;//c2 = c1.operator-()
c2.print();//-1-2i
Complex c3 = ~c1;//c3 = ::operator~(c1)
c3.print();
return 0;
}
2、前++/前–
操作数变。
表达式的值是运算以后的值。
表达式的值是左值,操作数的引用。
#include <iostream>
using namespace std;
class Complex{
public:
Complex(int r = 0, int i = 0) : m_r(r), m_i(i){}
void print(void) const{
cout << m_r << '+' << m_i << 'i' << endl;
}
Complex& operator++(void){
++m_r;
++m_i;
return *this;
}
friend Complex& operator-- (Complex& o){
--o.m_r;
--o.m_i;
return o;
}
private:
int m_r;
int m_i;
};
int main(void){
Complex c1(1,2);
Complex c2 = ++c1;//c2 = c1.operator++()
c1.print();//2+3i
c2.print();//2+3i
(++c1) = Complex(10,20);
c1.print();//10+20i
(++++++c1).print();
c2 = --c1;//c2=::operator
c1.print();//12+22i
c2.print();//12+22i
return 0;
}
3、后++/后–
操作数变。
表达式的值是运算以前的值。
表达式的值是右值。
#include <iostream>
using namespace std;
class Complex{
public:
Complex(int r = 0, int i = 0) : m_r(r), m_i(i){}
void print(void) const{
cout << m_r << '+' << m_i << 'i' << endl;
}
const Complex operator++(int){
Complex old(*this);
++m_r;
++m_i;
return old;
}
friend const Complex operator-- (Complex& o,int){
Complex old(o);
--o.m_r;
--o.m_i;
return old;
}
private:
int m_r;
int m_i;
};
int main(void){
Complex c1(1,2);
Complex c2 = c1++;//c2=c1.operator++(0)
c1.print();//2+3i
c2.print();//1+2i
//(c1++) = c2;
//c1++++++;
c2 = c1--;//c2::operator--(c1,0)
c1.print();//1+2i
c2.print();//2+3i
return 0;
}
四、其他操作符
1、下标操作符:[]
双目操作符,左操作数是一个具有容器特性的对象,右操作数是容器中特定数据元素的索引(基零的下标)。
下标表达式的值可以是左值,也可以是右值,由容器对象的常属性决定。常容器下标表达式的值是右值,非常容器下标表达式的值是左值。
#include <iostream>
using namespace std;
class Array{
public:
Array(size_t size = 1) : m_data(new int[size]){}
~Array(void){
if (m_data){
delete m_data;
m_data = NULL;
}
}
int& operator[] (size_t i){
return m_data[i];
}
const int& operator[] (size_t i) const{
return const_cast<Array&> (*this)[i];
}
private:
int* m_data;
};
int main(void){
Array arr(10);
for (size_t i = 0;i < 10;++i)
arr[i] = i;//arr.operator[](i) = i;
arr[0]++;
const Array& cr = arr;
for (size_t i = 0;i < 10;++i)
cout << cr[i] << ' ';
cout << endl;
//cr[0]++;
return 0;
}
2、函数操作符:()
如果为一个类定义了形如:
返回类型 operator() (形参表){…}
的操作符函数,那么这个类所实例化的对象就可以被当做函数使用。
3、解引用(*)和间接访问(->)操作符
以指针的方式使用类类型的对象。
#include <iostream>
#include <memory>
using namespace std;
class A{
public:
A(void){
cout << "构造" << endl;
}
~A(void){
cout << "析构" << endl;
}
void hello(void){
cout << "Hello,World!" << endl;
}
};
class PA{
public:
PA(A* p = NULL) : m_p(p){}
~PA(void){
if (m_p){
delete m_p;
m_p = NULL;
}
}
A& operator*(void) const{
return *m_p;
}
A* operator->(void) const{
return &(**this);
}
PA(PA& that) : m_p(that.release()){}
PA& operator= (PA& that){
if (&that != this)
reset(that.release());
return *this;
}
private:
A* m_p;
A* release(void){
A* p = m_p;
m_p = NULL;
return p;
}
void reset(A* p){
if (p != m_p){
delete m_p;
m_p = p;
}
}
};
void bar(auto_ptr<A> pa){
cout << "bar:";
pa->hello();
}
void foo(void){
//A* pa = new A;
//delete pa;
//A a;
PA pa(new A);
pa -> hello();//pa.operator->()->hello();
(*pa).hello();//pa.operator*().hello();
PA pb = pa;
pb->hello();//pa就不能用啦
auto_ptr<A> pa1(new A);//智能指针模板
pa1->hello();
auto_ptr<A> pa2 = pa1;
(*pa2).hello();
bar(pa2);
cout << pa2.get() << endl;//get()函数取指针的值
}
//smart_ptr,2011标准中的智能指针,可实现
int main(void){
foo();
return 0;
}
4、自定义类型转换和类型转换操作符
(1)通过单参构造实现自定义类型转换
如果A类中有一个可以接受B类对象作为唯一参数的构造函数,那么B类型的对象就可以根据该构造函数被转换为A类型。
通过explicit关键字,可以强制使用该构造函数所完成的类型转换必须显示进行。
(2)通过类型转换操作符函数实现自定义类型转换,如果A类中有一个形如
operator B (void) const{ … }
的操作符函数,那么A类型的对象就可以根据该函数被转换为B类型。
如果目标类型是类类型,源类型是基本类型,那么就只能通过在目标类型中定义以源类型为单参的构造函数实现类型转换。
如果目标类型是基本类型,源类型是类类型,那么就只能通过在源类型中定义以目标类型为函数名的类型转换操作符函数实现类型转换。
如果目标类型和源类型都是类类型,那么以上两种方法任取其一,但是不能同时使用。
如果目标类型和源类型都是基本类型,那么无法实现自定义类型转换。
#include <iostream>
using namespace std;
class Square{
public:
double operator() (double x){
return x * x;
}
};
class Integer{
public:
explicit Integer(int i = 0) : m_i(i){}//explicit关键字规定使用显示单参构造类型转换
void print(void) const{
cout << m_i << endl;
}
Integer& operator()(int i){
m_i += i;
return *this;
}
operator int(void) const{//类型转换操作符
return m_i;
}
private:
int m_i;
};
void foo(const Integer& i){
i.print();
}
Integer bar(void){
return Integer(300);
}
int main(void){
Square square;
cout << square(3) << endl;
//cout << square.operator()(3) << endl;
Integer i(10);
i(1)(2)(3)(17);
i.print();//33
i = (Integer)100;
i.print();
foo(static_cast<Integer> (200));
bar().print();
int n = i;
cout << n << endl;
return 0;
}
5、new/delete操作符
#include <iostream>
#include <cstdlib>
using namespace std;
class A{
public:
~A(void){}
static void* operator new (size_t size){
void* p = malloc(size);
cout << "自定义new:" << p << ' ' << size << endl;
return p;
}
static void operator delete(void* p){
cout << "自定义delete:" << p << endl;
free(p);
}
static void* operator new[] (size_t size){
void* p = malloc(size);
cout << "自定义的new[]:" << p << ' ' << size << endl;
return p;
}
static void operator delete[] (void* p){
cout << "自定义的delete[]:" << p << endl;
free(p);
}
private:
int m_i;
double m_d;
char m_c;
};
int main(void){
cout << sizeof(A) << endl;
A* pa = new A;
cout << pa << endl;
delete pa;
pa = new A[2];
cout << pa << endl;
delete[] pa;
return 0;
}
五、关于操作符重载的限制
1、至少有一个操作数是类类型的。
int a = 10, b = 20;
int c = a + b;//200
int operator+ (int a, int b){
return a * b;
}//ERROR!
2、不是所有的操作符都能重载。
:: —— 作用域限定
. —— 直接成员访问
.* —— 直接成员指针解引用
?: —— 三目运算符
sizeof —— 获取字节数
typeid —— 获取类型信息
3、不是所有的操作符都可以用全局函数的方式实现。
= —— 拷贝赋值
[] —— 下标操作符
() —— 函数操作符
-> —— 间接成员访问