为什么要使用运算符重载
C/C++的运算符,支持的数据类型,仅限于基本数据类型。
那么类与类之间可以进行加减乘除等运算吗?
一般来说C++是做不到的,但是我们可以通过运算符重载来实现这个功能。
运算符重载的基本用法:
①使用成员函数重载运算符
②使用非成员函数【友元函数】重载运算符
方式1:使用成员函数重载运算符
Cow.h
//需求:
// 规则:
// 一斤牛肉:2斤猪肉
// 一斤羊肉:3斤猪肉
#pragma once
class Pork;
class Goat;
class Cow
{
public:
Cow(int weight);
// 参数此时定义为引用类型,更合适,避免拷贝
Pork operator+(const Cow& cow); //同类型进行运算,很频繁
Pork operator+(const Goat& goat); //不同类型进行运算,比较少见
private:
int weight = 0;
};
Cow.h
#pragma once
class Pork;
class Goat;
class Cow
{
public:
Cow(int weight);
// 参数此时定义为引用类型,更合适,避免拷贝
Pork operator+(const Cow& cow); //同类型进行运算,很频繁
Pork operator+(const Goat& goat); //不同类型进行运算,比较少见
private:
int weight = 0;
};
Cow.cpp
#include "Cow.h"
#include "Pork.h"
#include "Goat.h"
Cow::Cow(int weight)
{
this->weight = weight;
}
// 规则:
// 一斤牛肉:2斤猪肉
// 一斤羊肉:3斤猪肉
Pork Cow::operator+(const Cow &cow)
{
int tmp = (this->weight + cow.weight) * 2;
return Pork(tmp);
}
Pork Cow::operator+(const Goat& goat)
{
// 不能直接访问goat.weight
//int tmp = this->weight * 2 + goat.weight * 3;
int tmp = this->weight * 2 + goat.getWeight() * 3;
return Pork(tmp);
}
Goat.h
#pragma once
class Goat
{
public:
Goat(int weight);
int getWeight(void) const;
private:
int weight = 0;
};
Goat.cpp
#include "Goat.h"
Goat::Goat(int weight) {
this->weight = weight;
}
int Goat::getWeight(void) const
{
return weight;
}
Pork.h
#pragma once
#include <iostream>
class Pork
{
public:
Pork(int weight);
std::string description(void);
private:
int weight = 0;
};
Pork.cpp
#pragma once
#include <iostream>
class Pork
{
public:
Pork(int weight);
std::string description(void);
private:
int weight = 0;
};
Pork.cpp
#include "Pork.h"
#include <sstream>
Pork::Pork(int weight)
{
this->weight = weight;
}
std::string Pork::description(void)
{
std::stringstream ret;
ret << weight << "斤猪肉";
return ret.str();
}
main.cpp
#include <iostream>
#include "Pork.h"
#include "Cow.h"
#include "Goat.h"
int main(void) {
Cow c1(100);
Cow c2(200);
// 调用c1.operator+(c2);
//相当于:Pork p = c1.operator+(c2);
Pork p = c1 + c2;
std::cout << p.description() << std::endl;
Goat g1(100);
p = c1 + g1;
std::cout << p.description() << std::endl;
system("pause");
return 0;
}
方式2:使用非成员函数【友元函数】重载运算符
Cow.h
#pragma once
class Pork;
class Goat;
class Cow
{
public:
Cow(int weight);
// 有友元函数实现运算符重载
friend Pork operator+(const Cow& cow1, const Cow& cow2);
friend Pork operator+(const Cow& cow1, const Goat& goat);
private:
int weight = 0;
};
main.cpp
#include <iostream>
#include "Pork.h"
#include "Cow.h"
#include "Goat.h"
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(void) {
Cow c1(100);
Cow c2(200);
Goat g1(100);
Pork p = c1 + c2;
std::cout << p.description() << std::endl;
p = c1 + g1; // 思考:如何实现:p = g1 + c1;
std::cout << p.description() << std::endl;
system("pause");
return 0;
}
其他文件不变。
两种方式的区别:
使用成员函数来实现运算符重载时,少写一个参数,因为第一个参数就是this指针。
两种方式的选择:
①一般情况下,单目运算符重载,使用成员函数进行重载更方便(不用写参数)
②一般情况下,双目运算符重载,使用友元函数更直观
方便实现a+b和b+a相同的效果,成员函数方式无法实现。
例如: 100 + cow; 只能通过友元函数来实现
cow +100; 友元函数和成员函数都可以实现
特殊情况:
(1)= () [ ] -> 不能重载为类的友元函数!!!(否则可能和C++的其他规则矛盾),只能使用成员函数形式进行重载。
(2)如果运算符的第一个操作数要求使用隐式类型转换,则必须为友元函数(成员函数方式的第一个参数是this指针)
注意:
同一个运算符重载, 不能同时使用两种方式来重载,会导致编译器不知道选择哪一个(二义性)