操作符重载C++

[程序设计教程用c++语言编程陈家骏]
1. 成员函数重载操作符:除“.”,“*”,“::”,“?:”外其他操作符都可重载
(1)a.双目操作符声明格式:
class <类名>
{
<返回值类型> operator #(<类型>);
}
b.双目操作符定义格式:
<返回值类型> <类名>::operator #(<类型>)
{
}
c.双目操作符使用格式:
<类名> a;
<类名> b;
a # b

a.operator(b);
(2)a.单目操作符重载声明格式:
class <类名>
{
<返回值类型>  operator #();
}
b.单目操作符定义格式:
<返回值类型> <类名>::operator #()
{
}
c.单目操作符使用格式:
<类名> a;
#a;

a.operator();
2.对于 前置++(--)和后置++(--)可采用如下形式区别定义:
class Counter
{
 int value;
public:
 Counter(){value=0;}
 Counter & operator ++()
 {
  value++;
  return *this;
 }
 Counter operator ++(int )
 {
  Counter temp=*this;
  ++(*this);
  return temp;
 }
};
Counter a,b,c;
b=++a;  //使用不带参数的++重载函数,前置++的计算结果为左值,返回为引用
c=a++;  //使用带int型参数的++重载函数,结果为临时对象
3. 全局函数重载操作符
(1)a.全局函数实现双目操作符重载格式:
<返回值类型> operator #(<类型1> <参数1>,<类型2> <参数2>){}  //类型1,类型2至少有一个是类、结构、枚举或它们的引用类型
b.全局函数实现双目操作符使用格式:
<类型1> a;
<类型2> b;
a # b;

operator #(a,b);
(2)a.全局函数实现单目操作符格式:
<返回值类型> opetator #(<类型> <参数>){}  //类型必须是类、结构、枚举或它们的引用类型
b.全局函数实现单目操作符使用格式:
<类型> a;
# a;

operator #(a);
为了区分前置++(--)和后置++(--),可定义一个重载函数,增加一个int参数。如后置++原型为:
<返回值类型> operator ++(<类型> <参数>, int);
除了=,(),[],->外,其他操作符既可作为成员函数,也可作为全局函数重载。这4个操作符只能作为成员函数来重载。另外某些情况下,操作符只能作为全局函数来重载,全局函数第一个参数可以为其他类型,而成员函数第一个参数规定为<类名> * const this。
4. 赋值操作符=:C++编译程序为每个类定义一个隐式的赋值操作符重载函数,逐个成员进行赋值,对应普通成员,采用通常的赋值操作,对于成员对象,调用该成员对象的赋值操作符重载函数赋值。对于包含成员对象的类来说,自己定义的赋值操作符重载函数不会自动调用成员对象的赋值操作符重载函数,必须要在自己定义的赋值操作符重载函数中显式给出。
一般来讲,需要自定义的拷贝构造函数的类通常也需要自定义的赋值操作符重载函数,拷贝构造函数和赋值操作符=重载函数的区别:
a.创建一个对象时,用另一个已存在的对象对其初始化,调用拷贝构造函数
b.对两个已存在的对象,通过赋值操作用一个对象改变另一个对象的状态时,调用赋值操作符重载函数。
赋值操作符只能作为非静态的成员函数来重载,不能被派生类继承。如果派生类没有定义赋值操作符重载函数,则对派生类对象的赋值操作将调用系统提供的赋值操作符=重载函数,而不是基类的赋值操作符重载函数
5. 类成员访问操作符->:->为双目操作符,第一个操作数为一个指向类或结构的指针,第二个操作数为第一个操作数指向的类或结构的成员。通过对->重载,可实现一种智能指针。->操作符只能作为非静态成员函数重载,重载时需要按单目操作符重载形式来实现,如:
class A
{
 int x,y;
public: 
 void f();
 void g();
};
class B
{
 A *p_a;
 int count;
public:
 B(A *p)
 {
  p_a=p;
  count=0;
 }
 A  *opetator ->()    //操作符->的重载函数
 {
  count++;
  return p_a;
 }
 int num_of_a_access()const
 {return count;}
};
A a;
B b(&a);     //b作为一个智能指针,指向了a
b->f();  //等价于b.operator->()->f();即访问a.f()
b->g();  //等价于b.operator->()->g();即访问a.g()
cout<<b.num_of_a_access();  //显示对象a的访问次数
上面重载过的->不能按照普通的间接访问成员操作来理解,对于b->f(),应按照b.operator()->f()来理解。对象a可以看成是一个共享资源,通过智能指针访问它,可实现对资源访问次数的统计。
6. new和delete重载:new的两个功能:为对象分配内存空间和调用对象类的构造函数。delete也有两个功能:调用对象析构函数和释放对象空间。对new和delete重载时,重载的是分配空间和释放空间的功能。
(1)new:必须作为静态成员函数来重载(static可以不写),格式为:
void * operator new(size_t size [,......]);
使用格式为:
A *p=new A;  //系统自动计算对象大小并传给形参size
如果new的重载函数有其他参数,则动态对象的创建格式为:
A *p=new (......) A;   //......表示传给new重载函数的其他实参
char buf[sizeof(A)];
A *p=new (buf) A(0);  //buf 是传给new重载函数的参数,0是传给构造函数的参数
对于上面创建的动态对象,其内存空间不是在程序堆区分配,而是由创建者提供,要使其消亡,不应该用delete,而是通过析构函数实现。一旦在一个类中重载了new后,通过new动态创建该类的对象时,将不再用内置的new操作来分配内存空间,而是调用自己的new重载函数分配空间。
(2)delete:必须作为静态成员函数来重载(static可以不写),格式 :
void operator delete(void *p[, size_t size]);  //
使用格式:
A *p =new A;
delete p;
delete撤销一个对象时,系统首先调用对象的析构函数,然后调用delete的重载函数并把该对象的地址传给它的第一个形参p,如果有第二个参数,系统会把欲撤销的对象的大小传给它。delete重载函数只能有一个,在某类中重载了delete后,通过delete撤销对象时将不再调用内置的delete操作。而是调用自己的delete重载函数。重载的new和delete是类的静态成员,可以被派生类继承。
7. 自定义类型转换操作符:对于用户自定义的类,c++提供了定义类型转换的机制,通过带一个参数的构造 函数和对类型转换操作符重载来实现一个类和其他类型之间的转换。
(1).带一个参数的构造函数用作类型转换:带一个参数的构造函数可以用作从一个基本类型或其他类到一个类的转换。如:
class Complex
{
 double real,imag;
public:
 Complex(){real=0;imag=0;}
 Complex(double r)
 {
  real=r;
  imag=0;
 }
 Complex(double r, double i)
 {
  real=r;
  imag=i;
 }
 friend Complex operator +(const Complex & x, Const Complex & y)
};
Complex operator +(Complex & x, Complex & y)
{
Complex temp;
temp.real=x.real+y.real;
temp.imag=x.imag+y.imag;
return temp;
}
Complex c1(1,2),c2,c3;
c2=c1+1.7;  //1.7隐式转换成一个复数对象Complex(1.7)
c3=1.5+c2;  //1.5隐式转换为一个复数对象Complex(1.5)
(2).自定义类型转换:在一个类中,可以对类型转换操作符进行重载,实现一个类到一个基本数据类型或一个其他类的转换,如:
class A
{
 int x,y;
public:
 operator int(){return x+y;}
};
A a;
int i=1;
int z=i+a;  //调用类型转换操作符int重载函数将a转换成int型数据
当类中同时出现具有一个参数构造函数和类型转换操作符重载函数时,会产生歧义,如:
class A
{
 int x,y;
public: 
 A(){x=0;y=0;}
 A(int i){x=i;y=0;}
 operator int(){return x+y;}
 friend A operator +(const A &a1, const A &a2);
};
A a;
int i=1,z;
z=a+i;  //a转换成i,还是i转换成a?
解决办法是:
z=(int)a+i;

z=a+(A)i;
也可以通过给A类的构造函数A(int i)加上explicit解决,即在函数开始加上explicit修饰符,其含义为:禁止把A(int i)当作隐式类型转换符来用。
8. 函数调用操作符():C++中,可以把函数调用作为一种操作符针对类来重载,如:
class A
{
 int value;
public:
 A(){value=0;}
 A(int x){value=x;}
 int operator ()(int x) {return x+value;}
};
A a(3);
cout<<a(10)<<endl;  //将a当作函数名,参数为10,相当于a.operator()(10);
函数调用操作符只能作为非静态成员函数重载,主要用于具有函数特征的对象或只有一个操作的对象。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值