一、定义:
运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
运算符重载后优先级不变,结合律不变。
只能重载C++提供的运算符,不能自定义运算符。
C++中除了成员运算符“.”,取指针成员值运算符“.*”、作用域运算符“::”、“sizeof()”运算符、条件运算符“?:”不能重载,其他运算符均能重载。
语法:返回类型 operator 运算符 ();
运算符重载是为了满足自定义类型的运算,一般定义为类中的成员函数。例如:
class Person {
public:
int m_A;
int m_B;
};
void test01() {
Person p1 = { 10,20 };
Person p2 = { 15,30 };
Person p3 = p1 + p2;
}
代码报错:没有与这些操作数匹配的运算符。就是因为目前 + 不能实现两个自定义类的相加。
二、+ 运算符重载
以上面代码为例:
- 成员函数实现重载
class Person {
public:
int m_A;
int m_B;
Person operator+(const Person &p) {
Person temp;
temp.m_A = this->m_A + p.m_A;
temp.m_B = this->m_B + p.m_B;
return temp;
}
Person operator+(int value) {
Person temp;
temp.m_A = this->m_A + value;
temp.m_B = this->m_B + value;
return temp;
}
};
- 全局函数实现重载
class Person {
public:
int m_A;
int m_B;
};
Person operator +(const Person &p1,const Person &p2) {
Person temp;
temp.m_A = p1.m_A + p2.m_A;
temp.m_B = p1.m_B + p2.m_B;
return temp;
}
Person operator +(const Person &p1, int value) {
Person temp;
temp.m_A = p1.m_A + value;
temp.m_B = p1.m_B + value;
return temp;
}
通过以上代码,可以实现p3=p1+p2,并且可以实现p3=p1+n;
总结:当双目运算符重载时,可用成员函数也可用全局函数,且能发生函数重载。-、*、/号同理。
三、<< 左移运算符重载
C++ 中 <<左移运算符和cout联合,作为输出指令使用 cout<< 。输出指令的本质就是对<<运算符进行了重载,使cout<<具备了输出功能。cout 是一个ostream类的实例化对象,ostream叫做输出流,在C++中用来输出,cout就是最典型的输出流对象。
通过对<<左移运算符的重载,可实现自定义类型的输出。
#include<iostream>
using namespace std;
#include<string>
class Person {
public:
string m_Name;
int m_Age;
//ostream &operator<<(ostream& cout) {
// cout << "姓名:" << m_Name << ",年龄:" << m_Age;
// return cout;
//}
};
//ostream类未提供public的默认无参构造,无法创建新对象,所以将cout引用
//作为参数传入函数;为实现连续输出,需返回cout的引用。
ostream &operator<<(ostream& cout,const Person& p) {
cout << "姓名:" << p.m_Name << ",年龄:" << p.m_Age ;
return cout;
}
void test01() {
Person p = { "zhangsan",19 };
cout << p << endl;
}
int main(int argc, char const **argv) {
test01();
system("pause");
return 0;
}
成员函数无法实现cout 和输出内容的前后位置关系,故以全局函数实现<<重载。当类中成员属性非public权限时,需将全局函数设置为类的友元函数。
友元函数:顾名思义就是这个全局函数是这个类的朋友,允许访问类中非public的成员属性。
#include<iostream>
using namespace std;
#include<string>
class Person {
friend ostream& operator<<(ostream&, const Person&);
public:
Person(string name, int age) :m_Name(name), m_Age(age) {};
private:
string m_Name;
int m_Age;
};
ostream &operator<<(ostream& cout,const Person& p) {
cout << "姓名:" << p.m_Name << ",年龄:" << p.m_Age ;
return cout;
}
void test01() {
Person p = { "zhangsan",19 };
cout << p << endl;
}
int main(int argc, char const **argv) {
test01();
system("pause");
return 0;
}
四、++、--运算符重载
自增自减运算符是单目运算符,且分为前置和后置,需要进行函数重载实现前置后置的区别。编译器提供了默认的后置运算符重载函数,以int虚参为区分实现函数重载。前置返回对象本身,具备连续运算功能,后置返回运算前的值,不具备连续运算功能,这也和原本的功能一致。上代码:
#include<iostream>
using namespace std;
#include<string>
class Person {
public:
int m_A;
int m_B;
Person& operator++() {//前置++重载,返回计算后的对象
this->m_A++;
this->m_B++;
return *this;
}
Person operator++(int) { //后置++重载,返回计算前的值,编译器提供了后置++函数的重载,以int虚参区分
Person temp=*this;
m_A++;
m_B++;
return temp;
}
};
ostream &operator<<(ostream& cout, const Person &p) {
cout << p.m_A << " " << p.m_B ;
return cout;
}
void test01() {
Person p1 = { 10,20 };
Person p2 = { 15,30 };
cout << p1++ <<" "<< p1 << endl;
cout << ++p2 <<" "<< p2 << endl;
}
int main(int argc, char const **argv) {
test01();
return 0;
}
五、 赋值运算符 = 的重载
当自定义类型中存在在堆区开辟的成员变量时,直接赋值就出现了浅拷贝情况,浅拷贝情况下,delete对象1,造成对象2中指针成员指向值改变。赋值运算符重载可以解决这个问题。但是,在未重构拷贝构造函数时,即使=已重载,Person p2=p1;该语句调用的依然是默认的拷贝构造函数,也就是浅拷贝。
#include<iostream>
using namespace std;
#include<string>
class Person {
public:
Person() {
m_Name = NULL;
}
Person(string name) {
m_Name = new string(name);
}
Person(const Person& p) {
this->m_Name = new string(*p.m_Name);
}
Person& operator=(const Person& p) {
if (m_Name) {
delete m_Name;
}
m_Name = new string(*p.m_Name);
return *this;
}
~Person() {
if (m_Name) {
delete m_Name;
}
m_Name = NULL;
}
string *m_Name;
};
void test01() {
Person p1("zhangsan");
Person p2 = p1 ;//未重构拷贝构造函数时,即使已进行了=重载,此语句依然是调用了默认的拷贝构造函数,也就是浅拷贝。
cout << "p1的m_Name=" << p1.m_Name << endl;
cout << "p2的m_Name=" << p2.m_Name << endl;
}
int main(int argc, char const **argv) {
test01();
return 0;
}
六、关系运算符重载
关系运算符重载需要确定比较条件,比如年龄。当p1.m_Age>p2.m_Age时,表示为p1>p2。
#include<iostream>
using namespace std;
#include<string>
class Person {
public:
int m_Age;
Person(int age):m_Age(age){}
bool operator>(const Person& p) {
return this->m_Age > p.m_Age;
}
bool operator<(const Person& p) {
return this->m_Age < p.m_Age;
}
bool operator==(const Person& p) {
return this->m_Age == p.m_Age;
}
};
void test01() {
Person p1(10);
Person p2(15);
cout << (p1 > p2) << endl;
cout << (p1 == p2) << endl;
cout << (p1 < p2) << endl;
}
int main(int argc, char const **argv) {
test01();
return 0;
}
七、函数调用符“()”的重载
目前我还没有发现特别的意义
#include<iostream>
using namespace std;
#include<string>
class Myprint {
public:
void operator()(const string& str) {
cout << str << endl;
}
};
class Myadd {
public:
int operator()(const int& a, const int& b) {
return a + b;
}
};
void test01() {
Myprint print;
print("Hello World!");
Myadd add;
cout << add(2, 3) << endl;
}
int main(int argc, char const **argv) {
test01();
return 0;
}
八、友元
友元包括:友元函数,友元类,友元成员函数。都是在类中用friend修饰,从而获得在该类中的特殊访问权限。
#include<iostream>
using namespace std;
#include<string>
class Person;
class Son {
public:
int& getPassword(Person &p);
};
class Person {
friend class Son;//友元类
friend string& getName(Person& p);//友元全局函数
friend int& Son::getPassword(Person& p);//友元成员函数
public:
Person() {};
Person(string name, int password) {
m_Name = name;
m_PassWord = password;
}
private:
string m_Name;
int m_PassWord;
};
int& Son::getPassword(Person& p) {//需要先声明函数原型为友元,再实现函数体
return p.m_PassWord;
}
string& getName(Person &p) {
return p.m_Name;
}
void test01() {
Person p("张三", 123456);
Son s;
cout << getName(p) << endl;
cout << s.getPassword(p) << endl;
}
int main(int argc, char const **argv) {
test01();
return 0;
}