C++篇——运算符重载

导语:
在C++中,运算符重载是一个很基础也很重要的内容,它的知识点很多容易忘,本次在学完C++之后来回顾C++运算符所有相关的知识,相信和第一次接触时的感觉会完全不一样。

运算符重载

C++预定义表示对数据的运算
• +, -,*, /, %, ^, &, ~, !, |, =, <<, >>, != ……
• 只能用于基本的数据类型
• 整型, 实型, 字符型, 逻辑型……
C++提供了数据抽象的手段:用户自己定义数据类型 – 类
调用类的成员函数 ->操作它的对象,这样不能直接对对象进行运算操作,于是,运算符重载就出来了。

运算符重载的好处?
对抽象数据类型也能够直接使用C++提供的运算符
• 程序更简洁
• 代码更容易理解

运算符重载的定义

• 对已有的运算符赋予多重的含义
• 使同一运算符作用于不同类型的数据时->不同类型的行为目的
• 扩展C++中提供的运算符的适用范围, 以用于类所表示的抽象数据类型
• 同一个运算符, 对不同类型的操作数, 所发生的行为不同

运算符重载的实质是函数重载
返回值类型 operator 运算符(形参表)
{
……
}

运算符重载在编译时:

•把含 运算符的表达式->对 运算符函数 的调用
• 把 运算符的操作数 -> 运算符函数的 参数
• 运算符被多次重载时, 根据 实参的类型 决定调用哪个运算符函数
• 运算符可以被重载成普通函数
• 也可以被重载成类的成员函数

运算符可以被重载成普通函数

class Complex {
public:
Complex( double r = 0.0, double i= 0.0 ){
 real = r;
 imaginary = i;
}
double real; // real part
double imaginary; // imaginary part
};
Complex operator+ (const Complex & a, const Complex & b)
{
 return Complex( a.real+b.real, a.imaginary+b.imaginary);
} // “类名(参数表)” 就代表一个对象
Complex a(1,2), b(2,3), c;
c = a + b;

也可以被重载成类的成员函数
注意:重载为成员函数时, 参数个数为运算符目数减一!

class Complex {
public:
Complex( double r= 0.0, double m = 0.0 ):
 real(r), imaginary(m) { } // constructor
Complex operator+ ( const Complex & ); // addition
Complex operator- ( const Complex & ); // subtraction
private:
double real; // real part
double imaginary; // imaginary part
};
// Overloaded addition operator
Complex Complex::operator+(const Complex & operand2) {
return Complex( real + operand2.real,
 imaginary + operand2.imaginary );
}
// Overloaded subtraction operator
Complex Complex::operator- (const Complex & operand2){
return Complex( real - operand2.real,
 imaginary - operand2.imaginary );
}
int main(){
 Complex x, y(4.3, 8.2), z(3.3, 1.1);
 x = y + z;		//x=y.operator + (z)
 x = y - z;		//x=y.operator - (z)
 return 0;
} 

赋值运算符的重载

赋值运算符 两边的类型 可以 不匹配
• 把一个 int类型变量 赋值给一个 Complex对象
• 把一个 char * 类型的字符串 赋值给一个 字符串对象
需要 重载赋值运算符 ‘=’
赋值运算符 “=” 只能重载为 成员函数

编写一个长度可变的字符串类String:
• 包含一个char * 类型的成员变量
-> 指向动态分配的存储空间
• 该存储空间用于存放 ‘\0’ 结尾的字符串

class String {
private:
char * str;
public:
String () : str(NULL) { } //构造函数, 初始化str为NULL
const char * c_str() { return str; }
char * operator = (const char * s);
~String( );
}; 
//重载 ‘=’  obj = “hello”能够成立
char * String::operator = (const char * s){
if(str) delete [] str;
if(s) { //s不为NULL才会执行拷贝
str = new char[strlen(s)+1];
strcpy(str, s);
}
else
str = NULL;
return str;
}
String::~String( ) {
if(str) delete [] str;
};
int main(){
String s;
s = “Good Luck,” ;
cout << s.c_str() << endl;
// String s2 = “hello!”; //这条语句要是不注释掉就会出错
s = "Shenzhou 8!";
cout << s.c_str() << endl;
return 0;
}

赋值运算符重载的意义:浅复制和深复制

浅复制:执行逐个字节的复制工作
深复制:将一个对象中指针变量指向的内容,复制到另一个对象中指针成员对象指向的地方
具体实现:

/*MyString S1, S2;
S1 = “this”;
S2 = “that”;
S1 = S2;*/
String & String::operator = (const String & s){
if(str == s.str) return * this;
if(str) delete [] str
;
if(s.str) { //s.str不为NULL才会执行拷贝
str = new char[strlen(s.str)+1];
strcpy( str,s.str);
}
else
str = NULL;
return * this;
}

对 operator = 返回值类型的讨论
为尽量保留运算符原本的特性和适应a=b=c的特殊情况,我们选择 string &作为返回值的类型。

为 String类编写 复制构造函数时;会面临和 ‘=’ 同样的问题, 用同样的方法处理:

String::String(String & s)
{
if(s.str) {
str = new char[strlen(s.str)+1];
strcpy(str, s.str);
}
else
str = NULL;
}

运算符重载为友元函数

通常, 将运算符重载为类的成员函数
重载为友元函数的情况:
• 成员函数不能满足使用要求
• 普通函数, 又不能访问类的私有成员
解决办法:将运算符+的普通函数重载为友元函数

流插入与流提取运算符重载

自定义输入与输出运算符

ostream & ostream::operator<<(int n)
{
…… //输出n的代码
return * this;
}
ostream & ostream::operator<<( const char * s )
{
…… //输出s的代码
return * this;
}
• 假定下面程序输出为 5hello, 该补写些什么
class CStudent{
public: int nAge;
};
int main(){
CStudent s ;
s.nAge = 5;
cout << s <<"hello";
return 0;
}
/*
ostream & operator<<( ostream & o,const CStudent & s){
o << s.nAge ;
return o;
}
*/

自增自减运算符的重载

自加 ++/自减 – 运算符有 前置/后置 之分
前置运算符作为一元运算符重载
• 重载为成员函数:
T & operator++();
T & operator–();
• 重载为全局函数:
T & operator++(T &);
T & operator—(T &);
++obj, obj.operator++(), operator++(obj) 都调用上述函数
自增自减运算符的重载代码实现

自加 ++/自减 -- 运算符有 前置/后置 之分
前置运算符作为一元运算符重载
• 重载为成员函数:
T & operator++();
T & operator--();
• 重载为全局函数:
T & operator++(T &);
T & operator—(T &);
++obj, obj.operator++(), operator++(obj) 都调用上述函数
CDemo CDemo::operator++(int k) { //后置 ++
CDemo tmp(*this); //记录修改前的对象
n++;
return tmp; //返回修改前的对象
}
CDemo& operator--
(CDemo & d) { //前置--
d.n--;
return d;
}
CDemo operator--
(CDemo & d, int) { //后置--
CDemo tmp(d);
d.n --;
return tmp;
} 

运算符重载需要注意的问题

C++不允许定义新的运算符
重载后运算符的含义应该符合日常习惯
• complex_a + complex_b
• word_a > word_b
• date_b = date_a + n
运算符重载不改变运算符的优先级
以下运算符不能被重载: “.”, “.*”, “::”, “?:”,
sizeof重载运算符(), [ ], ->或者赋值运算符=时, 重载函数必须声明为类的成员函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值