第七章

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 6

1.

一元运算符推荐用成员函数重载(只有一形参)
二元运算符推荐用友元函数重载(因需要有两形参)
一般来说,对于双目运算符,最好将其重载为友元函数,因为这样更方便些;而对于单
目运算符,则最好重载为成员函数。

2. 具体的:
双目运算符不能重载为友元函数的:赋值运算符=;
单目运算符只能重载为成员函数的:函数调用运算符()、下标运算符[]和指针->等;
只能重载为友元函数的:输出运算符<<,第一个操作数一定是 ostream 类型

必须是成员函数的:赋值(=)、下标([])、函数调用(())、成员访问箭头(->)
应该是成员函数的:如递增、递减和解引用运算符
应该是非成员函数的:如算术运算符、关系运算符、位运算符(具有对称性,也即操作
对象位置可以互换的)
必须为非成员函数时:含有类对象,且想把类对象和另一个对象
互换位置时
举例:如果 operator+是 A 类的成员,则
A c1(2,3);
A c2=c1+3.5;//①
A c3=3.5+c1;//②
上①式等价于 c1.operator+(3.5)
上②式等价于 3.5.operator+(c1)
显然不对。因此此时必须为非成员函数。为非成员函数时上①②式都等价于 operator+(3.5,c1) 或
operator+(c1,3.5)
唯一要求就是至少有一个运算对象是类类型,且两个运算对象都能准确无误地转换成
该类类型。
3. 运算符重载
(1)以非静态成员实现运算符重载
以类成员形式重载的运算符参数比实际参数少一个,第 1 个参数是以 this 指针隐式传递的。

(2)以友元函数实现运算符重载
如果将运算符函数作为类的友元重载,它需要的参数个数就与运算符实际需要的参数个数
相同。
声明为友元函数的好处:
1.和普通函数重载相比,它能够访问非公有成员。
2.将双目运算符重载为友元函数,这样就可以使用交换律。
弊端:
 友元可以像类成员一样访问类的成员和函数,但是使用不慎会造成破坏类的封装性。
(3)以普通函数实现运算符重载
这种形式无法访问非公有成员。
eg:
1 //作为普通函数重载(不推荐)
2 class Person{
3 public://注意,重载运算符为普通函数时,使用到的类成员必须为 public
4 string name;
5 int age;
6 public:
7 Person(const char* name, int age):name(name),age(age){}
8
9 };
10 bool operator<(const Person& a,const Person& b)
11 {
12 ...
13 }

重载二元运算符
4. aa@bb可解释成 aa.operator@(bb)
或解释成 operator@(aa,bb)
第 1 种形式是@被重载为类的非静态成员函数的解释方式,这种方式要求运算符@左边的参
数必须是一个对象,operator@是该对象的成员函数。
第 2 种形式是@作为类的友元或普通重载函数时的解释方式。

5. 作为类的非静态成员函数的二元运算符,只能够有一个参数,这个参数是运算符右边的
参数,它的第一个参数是通过 this 指针传递的,其重载形式如下:

class X{
……
T1 operator@(T2 b){ ……};
}

其中,T1 是运算符函数的返回类型,T2 是参数的类型,原则上 T1、T2 可以是任何数据类


型,但事实上它们常与 X 相同。c@d 等价于 c.operator@(d);

从形式上看,调用类在重载的二元运算符时只提供了一个参数,但实际上是两个参数,其
左参数虽然没有出现在参数表中,但编译器会通过 this 指针传递该参数。
两种方式调用在类中重载的二元运算符:
a@b 隐式调用
a.operator@(b)显式调用

6. 重载二元运算符为类的友元函数时需要两个参数,其形式如下:
class X{
……
friend T1 operator@(T2 a,T3 b);
}
T1 operator@(T2 a,T3 b){ ……}

T1、T2、T3 代表不同的数据类型,事实上它们常与类 X 相同。


重载一元运算符
7. 一元运算符只需要一个运算参数,如取地址运算符(&)、负数(-)、自增(++)、自减(--)
等。
一元运算符常见调用形式为:
@a 或 a@ //隐式调用形式
a.operator@() // 显式调用一元运算符@
其中的@代表一元运算符,a 代表操作数。
@a 代表前缀一元运算,如“++a”;
a@表示后缀运算,如“a++”。
@a 将被 C++解释为下面的形式之一
a.operator@()
operator@(a)

8. 一元运算符作为类成员函数重载时不需要参数,其形式如下:
class X{
……
T operator@(){……};
}
T 是运算符@的返回类型。从形式上看,作为类成员函数重载的一元运算符没有参数,但实
际上它包含了一个隐含参数,即调用对象的 this 指针。

9. 用友元函数重载一元运算符时需要一个参数。
Class X{
Friend T1 operator@(T2 a);
};
T1 operator@(T2 a){…}

T1 和 T2 常与类 X 的类型相同

在用友元和普通函数重载++、--这类一元运算符函数时,如果用值传递的方式设置函数的
参数,就可能会发生错误,不能把运算结果返回给调用对象 。
如果需要改变对象的数据成员值,就应以传引用形式传递对象参数。

特殊运算符重载
10. C++编译器可以通过在运算符函数参数表中是否插入关键字 int 来区分这两种方式
前缀
operator -- (); 成员函数
operator -- (X & x); 友元函数
后缀
operator -- (int); 成员函数
operator -- (X & x, int); 友元函数
eg:
void operator++ (int) { cout << "a" << endl; };//后缀
void operator++() { cout << "b" << endl; };//前缀
11. 在实现中,后缀操作会先构造一个临时对象,并将原对象保存 ,然后完成自增操作,
最后将保存对象原值的临时对象返回。
前缀
ClassName & ClassName::operator++()
{
ClassAdd(1);
return *this;
}
后缀
ClassName & ClassName::operator++(int)
{
ClassName temp(*this);
ClassAdd(1);
return temp;
}

12. 默认赋值运算符可能引起指针悬挂问题
解决方法:重载,使之可以删除悬挂的指针(赋值运算符重载只能用成员函数)
class string{
char *ptr;
public:
string(char * s)
{ ptr=new char[strlen(s)+1]; strcpy(ptr,s); }
~string( ) { delete ptr; }
string & operator=(const string & );
void print( ) { cout<<ptr<<endl; }
};
string & string::operator=(const string &s )
{
if(this==&s) return *this;
delete ptr; ptr=new char[strlen(s.ptr)+1];
strcpy(ptr,s.ptr); return *this;
}

在设计类似 String 这样的含有指针数据成员的类时,如果需要进行类对象之间的赋值操作,


就应该重载该类的赋值运算符。
赋值运算符是一个二元运算符,常返回本类对象的引用。形式如下:
class X
{
X& operator= (const X &source);
};

13. 赋值运算符运算是不能被继承的!
编译器会自动生成派生类的赋值运算符重载函数,将基类中的 operator=函数隐藏了。
一定要检查自赋值!
特别是加入引用后,自赋值看似更加合理,更加隐蔽
如 strA=strB,当 strA 是 strB 的引用时
黄金定律:
ClassName& ClassName::operator=(const ClassName& rhs)
{
自赋值检查
释放原有空间 & 申请新空间 & 数据复制
返回 *this
}

14. Copy constructor 和 operator= 的区别


当有新对象生成时, copy constructor 发生作用
已有对象间赋值时,operator=发生作用
X a;
X b(a);或 X b=a;  //调用 copy constructor
b = a; //调用 operator=
如果赋值运算符重载的参数不是引用,则先调用拷贝构造函数,再调用赋值运算符重载

15. [ ]是一个二元运算符,其重载形式如下:
class X{
……
X& operator[](int n);
};
重载[]需要注意的问题
① [ ]是一个二元运算符,其第 1 个参数是通过对象的 this 指针传递的,第 2 个参数代表
数组的下标
② 由于[ ]既可以出现在赋值符“=”的左边,也可以出现在赋值符“=”的右边,所以重
载运算符[ ]时常返回引用。
③ [ ]只能被重载为类的非静态成员函数,不能被重载为友元和普通函数。

16. 运算符( )是函数调用运算符,也能被重载。且只能被重载为类的成员函数。


运算符( )的重载形式如下:
class X{
……
X& operator( )(参数表);
};
其中的参数表可以包括任意多个参数。

运算符( )的调用形式如下:
X Obj; //对象定义
Obj.operator()(参数表); //调用形式 1
Obj(参数表); //调用形式 2
17. 重载输出运算符<<
输出运算符<<也称为插入运算符,通过输出运算符<<的重载可以实现用户自定义数据类型
的输出。
固定 可为引用也可不为
重载运算符<<的常见格式如下:
ostream &operator<<(ostream &os,classType object) {
……
os<< … //输出对象的实际成员数据
return os; //返回 ostream 对象
}

18. 重载输入运算符>>
输入运算符>>也称为提取运算符,用于输入数据。通过输入运算符>>的重载,就能够用它
输 入用户自定义的数据类型
固定 必须为引用,才可达到修改值的目的
其重载形式如下:
istream &operator>>(istream &is,class_name &object) {
……
is>> … //输入对象 object 的实际成员数据
return is; //返回 istream 对象
}

You might also like