author:&Carlton
tag:C++
topic:【C++】重载运算符,链式编程思想
website:黑马程序员C++
date:2023年7月21日
目录
前言
重载运算符既可以通过成员函数,也可以在全局函数对运算符重载,这些函数可以实现函数重载。
具体案例
加号运算符重载
在类的定义中对同类不同对象的私有属性不声明友元也能进行访问,
例如temp.m_age=p.m_age +m_age
可能是因为“本是同根生,相煎何太急”
进行链式编程时注意返回值类型为类Person,参数去掉引用,以便进行链式编程。
#include <iostream>
using namespace std;
class Person
{
//对全局函数声明友元
friend Person operator+(Person& p, int num);
friend Person operator+(Person& p1, Person& p2);
private:
int m_age;//类中可以访问私有属性
public:
Person(int age)
{
m_age = age;
}
//成员函数重载加号运算符
//Person operator+(Person& p)
//{
// Person temp(0);
// temp.m_age = p.m_age + m_age; //这里对象p和对象temp的m_age也能够访问,神奇
// return temp;
//}
//传入另外一个Person类对象,将两个对象的年龄属性值相加存给temp对象,然后返回person类的对象temp
int getage()
{
return m_age;
}
};
void test01()
{
Person p1(10);
Person p2(10);
Person p3(0);
p3 = p1 + p2;
//原型为p3=p1.operator+(p2);
cout << p3.getage() << endl;
p3 = p1 + 20;
cout << p3.getage() << endl;
}
//全局函数重载加号运算符
Person operator+(Person &p1,Person &p2)
{
Person temp(0);
temp.m_age = p1.m_age + p2.m_age;
return temp;
}
//重载运算符函数也可以实现函数重载
Person operator+(Person& p, int num)
{
Person temp(0);
temp.m_age = p.m_age + num;
return temp;
}
int main()
{
test01();
return 0;
}
左移运算符重载
只能通过全局函数重载左移运算符,注意函数参数和返回值的数据类型是引用形式还是值形式,其中cout均要用引用,使用同一个cout
链式编程思想要求我们返回值类型为ostream&,以便追加使用左移运算符。
#include <iostream>
using namespace std;
class Person
{
public:
int m_age;
Person(int age)
{
m_age = age;
}
};
//重载左移运算符只能在全局函数里,因为顺序问题,若在类成员函数中对象会在cout左边
ostream& operator<<(ostream &cout,Person &p) //注意引用,是使用同一个cout
{
cout << p.m_age;
return cout;
}
void test01()
{
Person p1(10);
Person p2(20);
cout << p1 << ' ' << p2 << endl; //链式编程思想,因此要求有类型为ostream*的返回值
}
int main()
{
test01();
return 0;
}
递增运算符重载
值得注意的几点:
①后置递增运算符不能重复使用,因为返回的是值,要有效重复使用需要结合引用,但这与我们返回初始值的目的相左。
②为了让后置递增后的对象也能使用重载后的左移运算符,重载左移运算符时第二个参数对Perosn类数据类型应该去掉引用,因为后置递增返回临时变量的值,临时变量被释放,不能对其引用。
③int为占位参数,用于区分重载前置和后置递增运算符函数。
#include <iostream>
using namespace std;
class Person
{
public:
int m_age;
Person(int age)
{
m_age = age;
}
//使用成员函数重载前置递增运算符
//返回引用,是为了对同一个数据进行递增操作
Person& operator++()
{
this->m_age++;
return *this;
}
//使用成员函数重载后置递增运算符
//int为占位参数,用于区分重载前置和后置递增运算符函数
Person operator++(int)
{
Person temp(0);
temp.m_age = this->m_age;
this->m_age++;
return temp;
}
};
//重载左移运算符
ostream& operator<<(ostream &cout, Person p) //为了让后置递增也能使用重载后的左移运算符,这里第二个参数应该去掉引用,因为后置递增返回临时变量的值,临时变量被释放,不能对其引用
{
cout << p.m_age;
return cout;
}
void test01()
{
Person p1(10);
cout << ++(++p1) << endl; //链式编程思想
Person p2(20);
//cout << (p2++)++<< endl; //不合法,后置递增运算符不能重复使用,因为返回的是值,要有效重复使用需要结合引用,但这与我们返回初始值的目的相左
cout << p2++ << endl;
cout << p2 << endl;
}
int main()
{
test01();
//int a = 1;
//cout << (a++)++ << endl; //不合法
//cout << a << endl;
return 0;
}
赋值运算符重载
赋值涉及深浅拷贝问题。在析构函数里释放内存区时要用深拷贝解决重载赋值运算符前编译器默认使用的浅拷贝带来的堆上内存区重复释放的问题。
#include <iostream>
using namespace std;
class Person
{
public:
int *m_age;
Person()
{
}
Person(int age)
{
m_age = new int(age);
}
//在析构函数释放在堆上开辟的内存区
~Person()
{
//若是浅拷贝会带来堆区内存被重复释放的问题
if (m_age != NULL)
{
delete m_age;
m_age = NULL;
}
}
//用成员函数重载赋值运算符,进行深拷贝操作
Person& operator=(Person &p)
{
//m_age = p.m_age;
//编译器默认就是浅拷贝
m_age = new int(*p.m_age);
//深拷贝操作
return *this;
}
};
ostream& operator<<(ostream &cout,Person &p)
{
cout << *p.m_age;
return cout;
}
void test01()
{
Person p1(10);
Person p2;
Person p3;
p3 = p2 = p1;//链式编程思想
cout << p1 << endl;
cout << p2 << endl;
cout << p3 << endl;
}
int main()
{
test01();
return 0;
}
关系运算符重载
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
int m_age;
string m_name;
Person(int age,string name)
{
m_age = age;
m_name = name;
}
//用成员函数重载关系运算符
bool operator==(Person& p)
{
if (m_age == p.m_age && m_name == p.m_name)
{
return true;
}
else
{
return false;
}
}
};
void compare(Person& p1, Person& p2)
{
if (p1 == p2)
{
cout << p1.m_name<<"和"<<p2.m_name << "是同一个人" << endl;
}
else
{
cout << p1.m_name << "和" << p2.m_name << "不是同一个人" << endl;
}
}
void test01()
{
Person p1(18, "Tom");
Person p2(18, "Tom");
Person p3(16, "Jerry");
compare(p1, p2);
compare(p1, p3);
}
int main()
{
test01();
return 0;
}
函数调用运算符重载
#include <iostream>
#include <string>
using namespace std;
class MyPrint
{
public:
MyPrint()
{
}
void operator()(string s)
{
cout << s << endl;
}
};
void test01()
{
MyPrint print;
print("Hello World!"); //伪函数,实际是对函数调用运算符进行了重载,本质是print.operator()("Hello World!");
MyPrint()("匿名对象也可以使用伪函数");
}
int main()
{
test01();
return 0;
}
反思与总结
熟悉函数返回值和参数有无用引用的区别,注意链式编程的需求。
欢迎指正与分享,谢谢!