《C++文章汇总》
上一篇介绍了《012-对象类型的参数和返回值、友元函数、内部类和局部类》,本文介绍运算符重载。
1.运算符重载
◼ 运算符重载(操作符重载):可以为运算符增加一些新的功能
class Point {
friend Point operator+(Point,Point);
private:
int m_x;
int m_y;
public:
int getX(){return m_x;};
int getY(){return m_y;};
Point(int x,int y):m_x(x),m_y(y){}
void display(){
cout << "(" << m_x <<", " << m_y << ")" << endl;
}
};
Point operator+(Point p1,Point p2){
return Point(p1.m_x+p2.m_x, p1.m_y+p2.m_y);
};
int main(){
Point p1(10,20);
Point p2(20,30);
Point p3 = p1+p2;
p3.display();
getchar();
return 0;
}
//输出
(30, 50)
若三个点一起相加,则operator+方法会进入两次,p1+p2+p3 <==> operator+(operator+(p1,p2),p3)
Point operator+(Point p1,Point p2){
cout << "Point operator+(Point p1,Point p2)" << endl;
return Point(p1.m_x+p2.m_x, p1.m_y+p2.m_y);
};
int main(){
Point p1(10,20);
Point p2(20,30);
Point p3(30,40);
Point p4 = p1+p2+p3;
p4.display();
getchar();
return 0;
}
//输出
Point operator+(Point p1,Point p2)
Point operator+(Point p1,Point p2)
(60, 90)
2.运算符重载完善
运算符重载中写成引用变量,参数前加const修饰,既能接收const修饰的对象,又能接收非const修饰的对象
class Point {
friend Point operator+(const Point &,const Point &);
private:
int m_x;
int m_y;
public:
int getX(){return m_x;};
int getY(){return m_y;};
Point(int x,int y):m_x(x),m_y(y){}
void display(){
cout << "(" << m_x <<", " << m_y << ")" << endl;
}
};
Point operator+(const Point &p1,const Point &p2){
cout << "Point operator+(Point p1,Point p2)" << endl;
return Point(p1.m_x+p2.m_x, p1.m_y+p2.m_y);
};
int main(){
Point p1(10,20);
Point p2(20,30);
Point p3(30,40);
Point p4 = p1+p2+p3;
//Point p5 = operator+(operator+(p1,p2),p3);
p4.display();
getchar();
return 0;
}
//输出
Point operator+(Point p1,Point p2)
Point operator+(Point p1,Point p2)
(60, 90)
拷贝构造函数为什么要这样写Point(const Point &p1)?
假设这样写Point(Point p1)会有什么后果?
Point p(10,20);
Point p0 = p;会调用拷贝构造函数,进入到参数Point p1 = p;此时又会调用拷贝构造函数,会进入死循环
const修饰的参数能接受const和非const参数
◼ 全局函数、成员函数都支持运算符重载
class Point {
private:
int m_x;
int m_y;
public:
int getX(){return m_x;};
int getY(){return m_y;};
Point(int x,int y):m_x(x),m_y(y){}
void display(){
cout << "(" << m_x <<", " << m_y << ")" << endl;
}
Point operator+(const Point &p){
return Point(m_x+p.m_x, m_y+p.m_y);
};
};
int main(){
Point p1(10,20);
Point p2(20,30);
Point p3(30,40);
Point p4 = p1+p2+p3;
p4.display();
getchar();
return 0;
}
//输出
(60, 90)
I.实现减号运算符重载
Point operator-(const Point &p){
return Point(m_x-p.m_x, m_y-p.m_y);
};
int main(){
Point p1(10,20);
Point p2(20,30);
Point p3(30,40);
Point p5 = p3 - p2;
p5.display();
getchar();
return 0;
}
//输出
(60, 90)
(10, 10)
会存在以下问题p1+p2 = Point(10,20)
,赋值没有意义,但编译器没有报错,在运算符函数重载前加const修饰符,const修饰的函数返回值无法修改,此时编译器会报错
加const前
加const后
此时p4 = p1 + p2 + p3又会报错,相当于p1.operator+(p2).operator+(p3),但p1.operator+(p2)返回值是一个const修饰的对象,是无法直接调用非const修饰的成员函数的,此时需要将重载函数变为const修饰的重载函数
class Point {
private:
int m_x;
int m_y;
public:
int getX(){return m_x;};
int getY(){return m_y;};
Point(int x,int y):m_x(x),m_y(y){}
void display(){
cout << "(" << m_x <<", " << m_y << ")" << endl;
}
const Point operator+(const Point &p) const{
return Point(m_x+p.m_x, m_y+p.m_y);
};
const Point operator-(const Point &p) const{
return Point(m_x-p.m_x, m_y-p.m_y);
};
};
int main(){
Point p1(10,20);
Point p2(20,30);
Point p3(30,40);
Point p4 = p1+p2+p3;//相当于p1.operator+(p2).operator+(p3),但p1.operator+(p2)返回值是一个const修饰的对象,是无法直接调用非const修饰的成员函数的,此时需要将重载函数变为const修饰的重载函数
// p1.operator+(p2).operator+(p3);
p4.display();
//p1+p2 = Point(10,20);//此处赋值没有任何意义,运算符重载函数前加const修饰
Point p5 = p3 - p2;
p5.display();
getchar();
return 0;
}
II.重载运算符加减混合运算
const Point operator+(const Point &p) const{
return Point(m_x+p.m_x, m_y+p.m_y);
};
const Point operator-(const Point &p) const{
return Point(m_x-p.m_x, m_y-p.m_y);
};
int main(){
Point p1(10,20);
Point p2(20,30);
Point p3(30,40);
Point p4 = p1+p2-p3;
p4.display();
getchar();
return 0;
}
//输出
(0, 10)
III.加等于,使用引用&不会产生中间对象
Point &operator+=(const Point &p){
m_x += p.m_x;
m_y += p.m_y;
return *this;
};
int main(){
Point p1(10,20);
Point p2(20,30);
(p1 += p2) = Point(50,60);
p1.display();
}
//输出
(50, 60)
IV.等于等于,加const后常量对象也能比较
bool operator==(const Point &p) const{
if(m_x == p.m_x && m_y == p.m_y)
return 1;
else
return 0;
};
int main(){
Point p1(10,20);
Point p2(20,30);
cout << (p1 == p2) << endl;
}
//输出
0
V.不等于,加const后常量对象也能比较
bool operator!=(const Point &p) const{
return (m_x != p.m_x)|| (m_y != p.m_y);
}
VI.负号
const Point operator-() const{
return Point(-m_x,-m_y);
}
int main(){
const Point p1(10,20);
Point p2(20,30);
Point p3 = -(-p1);
p1.display();
p3.display();
}
//输出
(10, 20)
(10, 20)
VII.++,--
//前置++
Point &operator++(){
m_x++;
m_y++;
return *this;
}
//后置++
const Point operator++(int){
//返回调用者之前的值
Point old(m_x,m_y);
m_x++;
m_y++;
return old;
}
int main(){
Point p1(10,20);
Point p2 = p1++ + Point(30,40);
p1.display();
p2.display();
}
//输出
(11, 21)
(40, 60)
VIII.<<,cout相当于Java的toString方法,OC的description方法
class Point {
friend void operator<<(ostream &,const Point &);
int m_x;
int m_y;
}
void operator<<(ostream &cout,const Point &p){
cout << "(" << p.m_x << "," << p.m_y << ")" << endl;
}
int main(){
Point p1(10,20);
Point p2 = p1++ + Point(30,40);
cout << p1;
cout << p2;
}
//输出
(11,21)
(40,60)
连续打印
class Point {
friend ostream &operator<<(ostream &,const Point &);
}
ostream &operator<<(ostream &cout,const Point &p){
cout << "(" << p.m_x << "," << p.m_y << ")";
return cout;
}
int main(){
Point p1(10,20);
Point p2 = p1++ + Point(30,40);
cout << p1 << p2 << 1 << 2 << 3;
}
//输出
(11,21)(40,60)123
系统自带的打印字符串函数要求左边cout修饰为非const,故重载打印运算符<<返回值前面不能加const,若加了const则连续打印cout << p1 << p2,cout< 禁止p1 = p2直接赋值,将重载函数私有化 同理,为什么cout重载后不能赋值,因为ostream库将cout重载函数私有化了 *rocket1 = *rocket2;//同一个对象,赋值操作没有意义,要禁止掉,将赋值操作符=私有化 仍旧可以调用拷贝构造函数,没有意义,要禁止掉 调用父类的运算符重载函数 ◼ 仿函数:将一个对象当作一个函数一样来使用 ◼ 有些运算符不可以被重载,比如 对象成员访问运算符:.//系统自带打印字符串要求左边cout修饰为非const
void operator<<(ostream &cout,const char *string){
}
VIV.>>,cin从键盘接收赋值
class Point {
friend istream &operator>>(istream &,Point &);
}
istream &operator>>(istream &cin,Point &p){
cin >> p.m_x;
cin >> p.m_y;
return cin;
}
int main(){
Point p1(10,20);
Point p2 = p1++ + Point(30,40);
cin >> p1 >> p2;
cout << p1 << p2 << endl;
getchar();
getchar();
return 0;
}
//输出
11 22 55 66
(11,22)(55,66)
VV.=说明,一般对象的符号如=重载后可以赋值,但cout重载后不能赋值
class Person{
int m_age;
int m_height;
public:
Person(int age,int height):m_age(age),m_height(height){
}
Person &operator=(const Person &person){
m_age = person.m_age;
return *this;;
}
void display(){
cout << "(" << m_age << "," << m_height << ")" << endl;
}
};
int main(){
Person p1(10,180);
Person p2(15,175);
(p1 = p2) = Person(50,20);
p1.display();
getchar();
return 0;
}
//输出
(50,180)
3.单例模式完善
4.赋值运算符注意点
class Person{
public:
int m_age;
Person &operator=(const Person &person){
m_age = person.m_age;
return *this;
}
};
class Student:public Person{
public:
int m_score;
Student &operator=(const Student &student){
Person::operator=(student);
m_score = student.m_score;
return *this;
}
};
int main(){
Student stu1;
stu1.m_age = 10;
stu1.m_score = 100;
Student stu2;
stu2 = stu1;
getchar();
return 0;
}
5.仿函数(函数对象)
◼ 对比普通函数,它作为对象可以保存状态int sum(int a,int b){
return a+b;
}
class Sum {
int m_age;
public:
int operator()(int a,int b){
cout << "operator()(int a,int b)" << endl;
return a+b;
}
void func(){
m_age = 10;
}
};
int main(){
Sum sum;
sum.func();
cout << sum(10,20) << endl;//相当于重载运算符()
sum(20,30);
// cout << sum.operator()(10,20) << endl;
getchar();
return 0;
}
//输出
operator()(int a,int b)
30
operator()(int a,int b)
6.运算符重载注意点
域运算符:::
三目运算符:?:
sizeof
◼ 有些运算符只能重载为成员函数,比如
赋值运算符:=
下标运算符:[ ]
函数运算符:( )
指针访问成员:->