C++运算符重载
什么是运算符重载
对象可以给对象赋值,是因为系统重载了符号“=”。
同样,对象之间可以进行加减乘除等操作,如:
Student s1,s2;
Student s3=s1-s2;
那s3的值到底是多少?
到底是s1和s2身高差?还是平均分差?还是其他属性的差值?
可重载的运算符:
运算符类型 | 运算符 |
---|---|
双目算术运算符 | + (加),-(减),*(乘),/(除),% (取模) |
关系运算符 | ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于) |
逻辑运算符 | ||(逻辑或),&&(逻辑与),!(逻辑非) |
单目运算符 | + (正),-(负),*(指针),&(取地址) |
自增自减运算符 | ++(自增),--(自减) |
位运算符 | | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移) |
赋值运算符 | =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>= |
空间申请与释放 | new, delete, new[ ] , delete[] |
其他运算符 | ()(函数调用),->(成员访问),,(逗号),[](下标) |
不可重载的运算符:
运算符 | 描述 |
---|---|
. | 成员访问运算符 |
.*, ->* | 成员指针访问运算符 |
:: | 域运算符 |
sizeof | 长度运算符 |
?: | 条件运算符 |
# | 预处理符号 |
一定要记住:
- 单目运算符最好重载为类的成员函数
- 双目运算符最好重载为类的友元函数
单目运算符
单目运算符只能与一个操作数相结合。
重载语法:
int operator++ () {
…
}
解释:
- 重载的符号为自增运算符++
- 函数名需要指定为operator,是固定的。
- 返回值的类型为int,可以自定义。
因为单目运算符通常是对类的成员进行修改,所以最好定义成类的成员函数。
示例-重载符负号:
class Point
{
private:
float x;
float y;
public:
Point(float X, float Y){
x=X;
y=Y;
}
void print(){
printf("%-7.2f%-7.2f\n",x,y);
}
Point operator- () //重载负号
{
return Point(-x,-y); //返回一个新对象,原对象不变
}
};
int main()
{
Point p1=Point(1,1);
Point p2=-p1;
p1.print(); //p1不变
p2.print(); //p2为p1取反
}
示例-重载自增/自减运算符:
class Student
{
private:
int id;
char* name;
int age;
public:
Student(int id, char* name,int age){
this->id=id;
this->name=name;
this->age=age;
}
void print(){
printf(“%-5d%-6s%d\n”,id,name,age);
}
int operator++ () //前置自增
{
age++;
return age;
}
int operator++ (int) //后置自增(int为固定用法)
{
age++;
return age-1;
}
};
int main()
{
Student s1=Student(1,"Tom",18);
cout<<"前置自增:"<<++s1<<endl;
s1.print();
cout<<"后置自增:"<<s1++<<endl;
s1.print();
}
双目运算符
双目运算符可以和两个操作数相结合。比如+,左操作数+右操作数。
语法
Point operator+(Point p1,Point p2){
……
}
因为双目运算符通常是两个类的状态进行结合,所以最好定义成类的友元函数。
示例-重载+号:
class Point
{
public:
float x;
float y;
Point(float X, float Y){
x=X;
y=Y;
}
void print(){
printf("%-7.2f%-7.2f\n",x,y);
}
friend Point operator+(Point p1,Point p2); //声明友元函数
};
//重载+号
//第一个参数是左操作数
//第二个参数是右操作数
Point operator+(Point p1,Point p2) //定义友元函数
{
return Point(p1.x+p2.x,p1.y+p2.y); //双目运算符一般不改变原对象的状态
}
int main()
{
Point p1=Point(1,1);
Point p2=Point(2,2);
Point p3=p1+p2; //p3为Point(3,3)
p3.print();
}
输入输出运算符重载
输出运算符重载
class Student
{
public:
char* name;
int age;
Student(char *NAME, int AGE){
name=NAME;
age=AGE;
}
};
ostream & operator<<(ostream &out, Student &obj){ //重载运算符<<
out << obj.name << " " << obj.age <<endl;
return out; //返回ostream,可以连续输出
}
int main(){
Student s1=Student("张三",18);
cout<<s1<<endl; //直接输出对象
}
解释:
参数1:ostream实例化的对象,名字可以自定义,这里为out,用于输出。
参数2:需要重载输出运算符的类
返回值:需要ostream &类型,这样就可以连续输出了。
输入运算符重载
class Student
{
public:
char name[10];
int age;
};
istream & operator>>(istream &in, Student &obj)
{
in >> obj.name>> obj.age;
if (!in)
{
obj = Student(); //如果没有输入则初始化对象
}
return in; //返回istream的对象,可以连续输入
}
int main(){
Student s1;
cin>>s1; //输入对象
cout<<s1.name<<" "<<s1.age<<endl;
}
解释:
与输出运算符重载不一样的是:需要判断用户是否直接回车,什么都没有输入
,还有类似的输入错误。
括号运算符重载
函数调用运算符()重载
class Student{
public:
char* name;
int age;
float avg;
Student(char* name, int age){
this->name=name;
this->age=age;
avg=0;
}
void operator()(int chinese, int math, int english){ //给avg赋值为平均分
avg=(chinese + math + english)/3.0;
}
};
int main(){
Student s1("张三",18);
s1(95,96,94); //使用符号()
cout<<s1.avg<<endl; //结果:95
}
解释:
相当于给对象添加了一个新的函数,只不过调用方式是:对象名()
下标运算符重载
class SafeArr{
public:
int arr[10];
SafeArr(){
for(int i = 0; i < 10; i++){
arr[i] = i;
}
}
int& operator[](int i){
if( i >= 10 || i<0 ){
cout << "索引超出范围" <<endl;
return arr[0]; //返回第一个元素
}
return arr[i];
}
};
int main(){
SafeArr A;
cout << "A[2] 的值为 : " << A[2] <<endl;
cout << "A[5] 的值为 : " << A[5]<<endl;
cout << "A[-1] 的值为 : " << A[-1]<<endl;
}