重载原因
C++ 中的运算符重载是一种特性,允许程序员定义自定义类类型的运算符操作。通过运算符重载,可以对类对象执行类似于内置类型的操作,例如加法、减法、乘法等。
运算符重载通过定义特定的成员函数或非成员函数来实现。成员函数的运算符重载为类的成员函数,且至少需要一个类对象作为操作数。而非成员函数的运算符重载则是独立于类的函数,其参数可以是类对象、指针或者引用。
运算符重载使用特定的语法,以便将运算符关联到相应的函数实现。例如,对于双目运算符(如+、-、*),可以通过重载成员函数或非成员函数的方式定义其操作。其中,成员函数的运算符重载使用成员函数的方式进行调用,而非成员函数的运算符重载则使用运算符的左侧对象作为第一个参数。
运算符重载提供了方便和直观的方式来执行类对象之间的操作。它可以使代码更具可读性,并提供更自然的语义,使得类的行为更接近内置类型。
然而,运算符重载也需要谨慎使用。过度使用运算符重载可能会导致代码可读性下降,使得代码难以理解和维护。因此,在进行运算符重载时,应注意遵循适当的语义和约定,并且避免使用过于复杂或混淆的运算符重载实现。
总结来说,C++ 中的运算符重载是一种强大的特性,允许程序员定义自定义类类型的运算符操作。通过合理和适度地使用运算符重载,可以提高代码的可读性和可维护性,使类对象的操作更加自然和直观。
一.加号运算符重载
对于内置的数据类型的表达式的运算符是不可能改变的
不要滥用运算符重载
1.1成员函数实现
成员函数实现时,即使成员函数是私有变量,也是可以实现运算符重载的,并且支持函数重载。
代码:
#include <iostream>
using namespace std;
class person {
friend void fun();
private:int age;int year;
public:person(int age, int year) :age(age), year(year) {}person(){}person operator+(person& p) {person m;m.age = this->age + p.age;m.year = this->year + p.year;return m;}
};
void fun() {person a(10, 90);person b(34, 89);person c = a + b;cout << c.age << ' ' << c.year << endl;
}
int main() {fun();return 0;
}
此时person c = a + b本质是person c=a.operator+(b);
person d = a + 10本质是person d=a.operator+(10);
2.2全局函数实现
全局函数实现时,重载运算符函数不能直接访问私有成员变量,需要在类中声明友元。
代码:
#include <iostream>
using namespace std;
class person {
friend void fun(); //设置全局函数是友元
friend person operator+(person& p1, person& p2);
friend person operator+(int p, person& p1);
private:int age;int year;
public:person(int age, int year) :age(age), year(year) {}person(){}
};person operator+(person& p1,person& p2) {person m;m.age =p1.age + p2.age;m.year =p1.age + p2.year;return m;
}person operator+(int p,person& p1) { //函数重载person m;m.age = p1.age + p;m.year = p1.year + p;return m;
}
void fun() {person a(10, 90);person b(34, 89);person c = a + b;person d = 10+ a; cout << c.age << ' ' << c.year << endl;cout << d.age << ' ' << d.year << endl;
}
int main() {fun();return 0;
}
此时,person c = a + b; 本质是person c =operator+(a,b);
person d = 10+ a; 本质是person d =operator+(10,a);
二.左移运算符重载
2.1成员函数实现
成员函数只能实现p<<cout......类型,cout不能放在左边;
代码:
#include <iostream>
using namespace std;
class person {
private:int age;int year;
public:person(int age,int year):age(age),year(year){}person() {};//返回ostream&是为了链式调用ostream& operator<<(ostream& cout) {cout << this->age << ' ' << this->year;return cout;}
};
void fun() {person p(23,78);p << cout << "成功" << endl;//本质p.operator<<(cout)<<"成功"<<endl;
}
int main() {fun();return 0;
}
p << cout << "成功" << endl的本质是p.operator<<(cout)<<"成功"<<endl;
2.2全局函数实现
全局函数可以实现cout在类的左边,也可以实现在类的右边
代码:
#include <iostream>
using namespace std;
class person {
friend ostream& operator<<(ostream& cout, person& p);
private:int age;int year;
public:person(int age, int year) :age(age), year(year) {}person() {};//返回ostream&是为了链式调用
};
ostream& operator<<(ostream& cout,person& p) {cout << p.age << ' ' << p.year;return cout;
}
void fun() {person p(23, 78);cout<< p << "成功" << endl;//本质p.operator<<(cout)<<"成功"<<endl;//本质operator<<(cout,p)<<"成功"<<endl;
}
int main() {fun();return 0;
}
三.++运算符重载
前置++重载不用参数,返回值是引用类型,后置++重载要int占位参数,返回值是值。
31.前置++
代码:
#include <iostream>
using namespace std;
class myint {
friend ostream& operator<<(ostream& cout, myint& p);
public:myint(int age,int year):age(age),year(year){}myint(){}//重载前置++,返回*this也是为了链式调用myint& operator++() {this->age++;return *this;}
private:int age;int year;
};
//重载<<运算符,注意是ostream& cout,是引用类型
ostream& operator<<(ostream& cout, myint &p) {cout << p.age << ' ' << p.year;return cout;
}
void fun() {myint p(10, 20);cout << ++(++p) << endl;;
}
int main() {fun();return 0;
}
返回追是引用类型,如果返回普通值的话,只能自增一次,第二次只是改变副本。
3.2后置 ++
代码:
#include <iostream>
using namespace std;
class myint {
friend ostream& operator<<(ostream& cout, myint& p);
friend void fun1();
public:myint(int age,int year):age(age),year(year){}myint(){}//重载前置++,返回*this也是为了链式调用myint& operator++() {this->age++;return *this;}//重置后置++,返回之前副本。myint operator++(int) {myint m = *this;this->age++;return m;}
private:int age;int year;
};
//重载<<运算符,注意是ostream& cout,是引用类型
ostream& operator<<(ostream& cout, myint &p) {cout << p.age << ' ' << p.year;return cout;
}
void fun() {myint p(10, 20);cout << ++(++p)<<endl;;
}
void fun1() {myint p(10, 20);cout << (p++).age << endl;cout << p.age << endl;
}
int main() {fun1();return 0;
}
后置++用int占位参数,用来区分和前置++的区别,并且要注意,返回的是值类型。
四.赋值运算符重载
在实例化类的对象时,会自动创建一个operator=函数,不过此时是浅拷贝,当遇到建立到堆上的数据类型时。调用赋值运算符会报错。此时需要重载赋值运算符,将浅拷贝改为深拷贝。
代码:
#include <iostream>
using namespace std;
class person {
public:int* age;int year;//有参构造,在堆区开辟person(int age, int year) {this->age = new int(age);this->year = year;}//深拷贝person(const person& p) {year = p.year;age = new int(*p.age);}//返回值是引用类型,链式调用person& operator=(const person& p) {if (this->age != NULL) {delete age;age = NULL;}year = p.year;//深拷贝age = new int(*p.age); return *this;}~person() {if (this->age != NULL) {delete age;age = NULL;}}
};
void fun() {person p1(43, 78);person p2(4, 7);person p3(89, 90);p3=p2 = p1;cout << *p2.age << ' ' << p2.year << endl;cout << *p3.age << ' ' << p3.year << endl;
}
int main() {fun();return 0;
}
p3=p2 = p1的本质是p3.operator=(p2.operator=(p1))
五.函数调用运算符重载
·函数调用运算符()也可以重载
·由于重载后使用的方式非常像函数的调用,因此称为仿函数,仿函数没有固定写法,非常灵活
代码:
#include <iostream>
using namespace std;
class person {
public:int age;person(int age) {this->age = age;}person(){}void operator()(string name) {cout << name << endl;}void operator()() {cout << "年龄是:" << age << endl;}
};
void fun() {person p1(10);person p2(20);p1("name_name");//匿名对象person()("匿名调用");p1();p2();
}
int main() {fun();return 0;
}
六.关系运算符重载
作用:重载关系运算符,可以让两个自定义类型对象进行对比操作
代码:
#include <iostream>
using namespace std;
class person {
public:int age;string name;person(int age, string name) :age(age), name(name) {}//重载==号,函数设置为常函数是为了防止误操作bool operator==(const person& p) const{if (age == p.age && name == p.name) {return true;}return false;}//重载!=号bool operator!=(const person& p) const {if (age == p.age && name == p.name) {return false;}return true;}//重载>号bool operator>(const person& p) const {if (age == p.age) {return name > p.name;}else {return age > p.age;}}};
void fun() {person p1(40, "tom");person p2(10, "aom");if (p1 == p2) {cout << "p1=p2" << endl;}else {cout << "p1!=p2" << endl;}if (p1 != p2) {cout << "p1!=p2" << endl;}else {cout << "p1==p2" << endl;}if (p1 > p2) {cout << "p1 > p2" << endl;}else {cout << "p1 <= p2" << endl;}
}
int main() {fun();return 0;
}