C++基础知识学习记录—运算符重载
1、概念
1、C++允许把运算符看做为一个函数,因此绝大多数运算符也支持函数重载。
2、C++中预定义的运算符只能对基本数据类型进行操作,但是对于很多用户自定义的类型,也需要类似的运算操作,此时就可以对这些运算符进行重载,赋予新的功能,根据新的数据类型执行特定的操作
3、运算符重载的本质是函数重载,它也是C++多态的一种体现
4、运算符重载增强了C++的可扩充性,使得C++代码更加直观、易读
C++提供的运算符重载机制,重载运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要重载的运算符共同组成。和其他函数一样,重载运算符的函数也包括返回类型、参数列表及函数体。
可以被重载的运算符:
算术运算符:+、-、*、/、%、++、--
位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)
逻辑运算符:!、&&、||
比较运算符:<、>、>=、<=、==、!=
赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=
其他运算符:[]、()、->、,、new、delete、new[]、delete[]
不能被重载的运算符:
成员运算符“.”、指针运算符“*”、三目运算符“? :”、sizeof、作用域“::”
运算符重载既可以通过友元函数实现,又可以通过成员函数函数。
2、友元函数运算符重载
#include <iostream>
#include <string>
using namespace std;
class Test
{
private:
int num;
public:
Test(int num)
:num(num){ }
//num的读接口
int get_num() const
{
return this->num;
}
//+运算符重载的友元说明
friend Test operator +(const Test& t1,const Test& t2);
//前置++运算符重载的友元说明
friend Test operator ++(Test& t);
//后置++ 运算符重载友元说明 int是一个占位符,用来和前置++加以区分
friend Test operator ++(Test& t,int);
};
int main()
{
Test t1(11);
Test t2(22);
Test t3=t1+t2;
cout << t3.get_num() << endl;//33
Test t4(44);
Test t5=++t4;
cout << t5.get_num() << endl;//45
cout << t4.get_num() << endl;//45
Test t6(66);
Test t7=t6++;
cout << t7.get_num() << endl;//66
cout << t6.get_num() << endl;//67
return 0;
}
Test operator +(const Test& t1,const Test& t2)
{
return t1.num+t2.num;
}
Test operator ++(Test& t)
{
return ++t.num;
}
Test operator ++(Test& t,int)
{
return t.num++;
}
3、成员函数运算符重载
成员函数,默认都有一个隐含的this指针,可以比友元函数重载少一个参数,隐含的this指针作为成员函数的第一个参数存在。
#include <iostream>
#include <string>
using namespace std;
class Test
{
private:
int num;
public:
Test(int num)
:num(num){ }
//num的读接口
int get_num() const
{
return this->num;
}
//+运算符重载的友元说明
Test operator +(const Test& t);
//前置++运算符重载的友元说明
Test operator ++();
//后置++ 运算符重载友元说明 int是一个占位符,用来和前置++加以区分
Test operator ++(int);
};
Test Test::operator +(const Test& t)
{
return this->num+t.num;
}
Test Test::operator ++()
{
return ++this->num;
}
Test Test::operator ++(int)
{
return this->num++;
}
int main()
{
Test t1(11);
Test t2(22);
Test t3=t1+t2;
cout << t3.get_num() << endl;//33
Test t4(44);
++t4;
cout << t4.get_num() << endl;//45
Test t5(55);
t5++;
cout << t5.get_num() << endl;//56
return 0;
}
4、特殊情况
1、赋值运算符重载
赋值运算符重载 = ,只能使用成员函数运算符重载,当程序员在一个类中不手写赋值运算符重载时,编译器会自动添加,默认的赋值运算符重载函数,其内容类似于拷贝构造函数。
作用:用于把一个对象的值赋值给另一个对象
形式:T& operator =(const T& t) //T可以是任意类型
特点:是类内函数,只支持成员函数重载
不显示给出赋值运算符函数时,编译器会给出默认的赋值运算符函数,完成对象间的赋值。
但是当属性有指针类型的时候,这时需要显示写出赋值运算符函数,类似于浅拷贝出现的问题
注意,当成员变量出现指针时,需要程序员手动编写赋值运算符重载逻辑,防止浅拷贝出现。
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class Test
{
private:
int num;
char *name;
public:
//深拷贝构造函数
Test(int num,char* name)
{
this->num=num;
this->name=new char [20];
strcpy(this->name,name);
}
//手动添加编译器自带赋值运算符重载 浅拷贝
/*Test& operator =(const Test& t)
{
this->num=t.num;
this->name=t.name;
return *this;
}*/
//手写赋值运算符重载 实现深拷贝
Test& operator =(const Test& t)
{
this->num=t.num;
this->name=new char[20];
cout << "********" << endl;
strcpy(this->name,t.name);
return *this;
}
//num 读接口
int get_num() const
{
return this->num;
}
//name读接口
char* get_name() const
{
return this->name;
}
};
int main()
{
char ch[20]="admin";
Test t1(2,ch);
Test t2(3,"nancy");
t2=t1;
cout << t2.get_num() << endl;
cout << t2.get_name() << endl;
cout << endl;
strcpy(t1.get_name(),"tttttt");
cout << t1.get_name() << endl;
cout << t2.get_name() <<endl;
cout << endl;
strcpy(ch,"wwww");
cout << t1.get_name() << endl;
cout << t2.get_name() <<endl;
return 0;
}
2、类型转换运算符重载
这种情况的写法比较特殊,且必须使用成员函数运算符实现重载。
作用:把自定义类型转成任意类型
特点:
1、只支持成员函数重载
2、不需要写返回值类型
#include <iostream>
using namespace std;
class Test{
private:
int num;
public:
Test(int num)
:num(num){ }
//num 读接口
int get_num() const
{
return num;
}
//(int)t 转成整形的运算符重载
operator int()
{
return this->num;
}
};
int main()
{
Test t1(100);//创建对象
Test t2 = 90;//隐式调用构造函数 也会创建对象
cout << t2.get_num() << endl;
int b(t1); //会出现类型转换 把对象类型t转换成整形
int res=(int)t2;//强制类型转换
//cout << t << endl
cout << res << endl;
cout << b << endl;
return 0;
}
3、运算符重载的总结
● 运算符重载只能限制在C++已有的运算符范围内,即不能创建新的运算符。
● 运算符重载不能改变运算符的优先级和结合性。
● 运算符重载不能改变运算符的操作数和语法结构。
● 无法更改已有的基本数据类型运算规则,只能应用于包含用户自定义类型的运算。
● 运算符重载应该保持与原有运算符功能类似,避免没有目的地滥用运算符重载。
● 运算符重载函数不支持参数默认值的设定。
● 一般情况下,单目运算符建议使用成员函数重载,双目运算符使用友元函数重载