C++运算法重载
C/C++的运算符,支持的数据类型,仅限于基本数据类型。
问题:
解决方案:使用运算符重载
那些可以重载
为了防止对标准类型进行运算符重载,
C++规定重载运算符的操作对象至少有一个不是标准类型,而是用户自定义的类型比如不能重载 1+2 但是可以重载
cow + 2 和 2 + cow // cow 是自定义的对象
不能改变原运算符的语法规则, 比如不能把双目运算符重载为单目运算
不能改变原运算符的优先级
不能创建新的运算符,比如 operator*就是非法的, operator是可以的
不能对以下这四种运算符,使用友元函数进行重载= 赋值运算符,()函数调用运算符,[ ]下标运算符,->通过指针访问类成员
不能对禁止重载的运算符进行重载
运算符 |
是否可重载 |
说明 |
. |
不可重载 |
成员访问运算符 |
:: |
不可重载 |
作用域解析运算符 |
.* |
不可重载 |
成员指针访问运算符 |
->* |
不可重载 |
成员指针访问运算符 |
?: |
不可重载 |
条件运算符 |
sizeof |
不可重载 |
大小查询运算符 |
typeid |
不可重载 |
类型信息运算符 |
= |
可重载 |
赋值运算符 |
() |
可重载 |
函数调用运算符 |
[] |
可重载 |
下标运算符 |
-> |
可重载 |
成员访问运算符 |
new |
可重载 |
动态内存分配运算符 |
delete |
可重载 |
动态内存释放运算符 |
+ |
可重载 |
加法运算符 |
- |
可重载 |
减法运算符 |
* |
可重载 |
乘法运算符 |
/ |
可重载 |
除法运算符 |
% |
可重载 |
取模运算符 |
++ |
可重载 |
自增运算符 |
-- |
可重载 |
自减运算符 |
== |
可重载 |
等于运算符 |
!= |
可重载 |
不等于运算符 |
> |
可重载 |
大于运算符 |
< |
可重载 |
小于运算符 |
>= |
可重载 |
大于等于运算符 |
<= |
可重载 |
小于等于运算符 |
&& |
可重载 |
逻辑与运算符 |
|| |
可重载 |
逻辑或运算符 |
! |
可重载 |
逻辑非运算符 |
~ |
可重载 |
按位取反运算符 |
& |
可重载 |
按位与运算符 |
| |
可重载 |
按位或运算符 |
^ |
可重载 |
按位异或运算符 |
<< |
可重载 |
左移运算符 |
>> |
可重载 |
右移运算符 |
, |
可重载 |
逗号运算符 |
加减重载(顺便介绍以下重载的基本实现)
使用成员函数重载运算符
#include<iostream> #include <sstream> using namespace std;
class Goat{ public: Goat(int weight){ this->weight = weight; }; int getWeight(void) const{ return this->weight; }; private: int weight = 0; };
class Pork { public: Pork(int weight){ this->weight = weight; }; string description(void){ stringstream ret; ret << weight << "斤猪肉"; return ret.str(); }; private: int weight = 0; };
class Cow { public: Cow(int weight){ this->weight = weight; }; Pork operator+(const Cow& cow){ int tmp = (this->weight + cow.weight) * 2; return Pork(tmp); };
Pork operator+(const Goat& goat){ int tmp = this->weight * 2 + goat.getWeight() * 3; return Pork(tmp); }; private: int weight = 0; };
int main(){ Cow c1(100); Cow c2(200); Pork p = c1 + c2; cout << p.description() << endl; Goat g1(100); p = c1 + g1; cout << p.description() << endl; return 0; }
|
使用友元函数重载运算符
#include<iostream> #include <sstream> using namespace std;
class Goat{ public: Goat(int weight){ this->weight = weight; }; int getWeight(void) const{ return this->weight; }; private: int weight = 0; };
class Pork { public: Pork(int weight){ this->weight = weight; }; string description(void){ stringstream ret; ret << weight << "斤猪肉"; return ret.str(); }; private: int weight = 0; };
class Cow { public: Cow(int weight){ this->weight = weight; };
friend Pork operator+(const Cow& cow1, const Cow& cow2); friend Pork operator+(const Cow& cow1, const Goat& goat);
private: int weight = 0; };
Pork operator+(const Cow &cow1, const Cow &cow2) { int tmp = (cow1.weight + cow2.weight) * 2; return Pork(tmp); } Pork operator+(const Cow& cow1, const Goat& goat) { int tmp = cow1.weight * 2 + goat.getWeight() * 3; return Pork(tmp); }
int main(){ Cow c1(100); Cow c2(200); Pork p = c1 + c2; cout << p.description() << endl; Goat g1(100); p = c1 + g1; cout << p.description() << endl; return 0; }
|
区别:
1.使用成员函数来实现运算符重载时,少写一个参数,因为第一个参数就是 this 指针。
两种方式的选择:
一般情况下,单目运算符重载,使用成员函数进行重载更方便(不用写参数)
一般情况下,双目运算符重载,使用友元函数更直观
方便实现 a+b 和 b+a 相同的效果,成员函数方式无法实现。
例如: 100 + cow; 只能通过友元函数来实现
cow +100; 友元函数和成员函数都可以实现特殊情况:
= () [ ] -> 不能重载为类的友元函数!!!(否则可能和 C++的其他规则矛盾),只能使用成员函数形式进行重载。
如果运算符的第一个操作数要求使用隐式类型转换,则必须为友元函数(成员函数方式的第一个参数是 this 指针)
注意: 同一个运算符重载, 不能同时使用两种方式来重载,会导致编译器不知道选择哪一个(二义性)
重载复制运算符=
注意:
#include<iostream> #include<string> #include <string.h> #include <sstream> using namespace std;
class Boy{ private: char* name; int age; int salary; int darkHorse; unsigned int id; static int LAST_ID;
public: Boy(const char* name=NULL, int age=0, int salary=0, int darkHorse=0){ if (!name) { name = "未命名"; } this->name = new char[strlen(name) + 1]; strcpy(this->name, name); this->age = age; this->salary = salary; this->darkHorse = darkHorse; this->id = ++LAST_ID; };
~Boy(){ if (name) { delete name; } }; Boy& operator=(const Boy& boy){ if (name) { delete name; } name = new char[strlen(boy.name) + 1]; strcpy(name,boy.name); this->age = boy.age; this->salary = boy.salary; this->darkHorse = boy.darkHorse; this->id = boy.id;
return *this; }; string description(){
std::stringstream ret; ret << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:" << salary << "\t黑马系数:" << darkHorse; return ret.str(); }; };
int Boy::LAST_ID = 0;
int main() {
Boy boy1("hacker", 38, 58000, 10); Boy boy2, boy3; std::cout << boy1.description() << std::endl; std::cout << boy2.description() << std::endl; std::cout << boy3.description() << std::endl; boy3 = boy2 = boy1; std::cout << boy2.description() << std::endl; std::cout << boy3.description() << std::endl;
return 0; }
|
重载复制运算符=
#include<iostream> #include<string> #include <string.h> #include <sstream> using namespace std;
class Boy{ private: char* name; int age; int salary; int darkHorse; unsigned int id; static int LAST_ID;
int power() const{ int value = salary * darkHorse + (100 - age) * 100; return value; };
public: Boy(const char* name=NULL, int age=0, int salary=0, int darkHorse=0){ if (!name) { name = "未命名"; } this->name = new char[strlen(name) + 1]; strcpy(this->name, name); this->age = age; this->salary = salary; this->darkHorse = darkHorse; this->id = ++LAST_ID; };
~Boy(){ if (name) { delete name; } }; string description(){
std::stringstream ret; ret << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:" << salary << "\t黑马系数:" << darkHorse; return ret.str(); };
bool operator<(const Boy& boy){ return this->power() > boy.power(); }; bool operator>(const Boy& boy){ return this->power() < boy.power(); }; bool operator==(const Boy& boy){ return this->power() == boy.power(); }; };
int Boy::LAST_ID = 0;
int main() { Boy boy1("hacker", 38, 58000, 5); Boy boy2("Jack", 25, 50000, 10);
if (boy1 > boy2) { std::cout << "选择boy1" << std::endl; } else if (boy1 == boy2) { std::cout << "难以选择" << std::endl; }else{ std::cout << "选择boy2" << std::endl; }
return 0; }
|
重载运算符[ ]
#include<iostream> #include<string> #include <string.h> #include <sstream> using namespace std;
class Boy{ private: char* name; int age; int salary; int darkHorse; unsigned int id; static int LAST_ID;
int power() const{ int value = salary * darkHorse + (100 - age) * 100; return value; };
public: Boy(const char* name=NULL, int age=0, int salary=0, int darkHorse=0){ if (!name) { name = "未命名"; } this->name = new char[strlen(name) + 1]; strcpy(this->name, name); this->age = age; this->salary = salary; this->darkHorse = darkHorse; this->id = ++LAST_ID; };
~Boy(){ if (name) { delete name; } }; string description(){
stringstream ret; ret << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:" << salary << "\t黑马系数:" << darkHorse; return ret.str(); };
int operator[](string index){ if (index == "age") { return age; }else if(index == "salary") { return salary; }else if(index == "darkHorse") { return darkHorse; } else if(index == "power") { return power(); }else{ return -1; } };
int operator[](int index){ if (index == 0) { return age; }else if(index == 1) { return salary; }else if(index == 2) { return darkHorse; }else if(index == 3) { return power(); } else { return -1; } };
};
int Boy::LAST_ID = 0;
int main() {
Boy boy1("hacker", 38, 58000, 5); Boy boy2("Jack", 25, 50000, 10); cout << "age:" << boy1["age"] << endl; cout << "salary:" << boy1["salary"] << endl; cout << "darkHorse:" << boy1["darkHorse"] << endl; cout << "power:" << boy1["power"] << endl; cout << "[0]:" << boy1[0] << endl; cout << "[1]:" << boy1[1] << endl; cout << "[2]:" << boy1[2] << endl; cout << "[3]:" << boy1[3] << endl;
return 0; }
|
重载<<和>> 了解
为了更方便的实现复杂对象的输入和输出。
friend ostream& operator<<(ostream& os, const Boy& boy); friend istream& operator>>(istream& is, Boy& boy);
ostream& operator<<(ostream& os, const Boy& boy) { os << "ID:" << boy.id << "\t姓名:" << boy.name << "\t年龄:" << boy.age << "\t薪资:" << boy.salary << "\t黑马系数:" << boy.darkHorse; return os; } istream& operator>>(istream& is, Boy& boy) { string name2; is >> name2 >> boy.age >> boy.salary >> boy.darkHorse; boy.name = (char*)malloc((name2.length()+1) * sizeof(char)); strcpy_s(boy.name, name2.length() + 1, name2.c_str()); return is; }
|
普通类型 => 类类型 了解
调用对应的只有一个参数【参数的类型就是这个普通类型】的构造函数
Boy boy1 = 10000;
构造函数Boy(int); Boy boy2 = "hacker"
构造函数 Boy(char *);
Boy(const char* name, int age, int salary, int darkHorse); ~Boy(); Boy(int salary); Boy(const char* name);
Boy::Boy(int salary) { const char *defaultName = "未命名"; name = new char[strlen(defaultName) + 1]; strcpy_s(name, strlen(defaultName) + 1, defaultName); age = 0; this->salary = salary; darkHorse = 0; this->id = ++LAST_ID; } Boy::Boy(const char* name) { this->name = new char[strlen(name) + 1]; strcpy_s(this->name, strlen(name) + 1, name); age = 0; this->salary = 0; darkHorse = 0; this->id = ++LAST_ID; }
|
类类型 => 普通类型 了解
调用特殊的运算符重载函数,类型转换函数,不需要写返回类型
类型转换函数:operator 普通类型 ( )
Boy boy1(“hacker”, 28, 10000, 5); int power = boy1; char *name = boy1;
Boy::operator int() const { return power(); } Boy::operator char* () const { return name; }
operator int() const; operator char* () const;
Boy::operator int() const { return power(); } Boy::operator char* () const { return name; }
|