文章目录
- C++ 重载运算符和重载函数
- C++ 中的函数重载
- 可重载运算符/不可重载运算符
- 运算符重载实例
- 运算符重载 | C++ 一元运算符重载
- 运算符重载 | C++ 输入/输出运算符重载
- 运算符重载 | C++ ++ 和 — 运算符重载
- 实例8:
- 实例9 (++ 重载):
- 实例10(–重载):
- 运算符重载 | C++ 函数调用运算符 () 重载
- 运算符重载 | C++ 下标运算符 [] 重载
- 运算符重载 | C++ 类成员访问运算符 -> 重载
C++ | C++ 重载运算符和重载函数
C++ 重载运算符和重载函数
C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。
当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策。
C++ 中的函数重载
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。
您不能仅通过返回类型的不同来重载函数。
实例1:
/*******************************************************************
* > File Name: classOverload.cpp
* > Create Time: 2021年09月 5日 8:47:06
******************************************************************/
#include
using namespace std;
class printData
{
public:
void print(int i){cout void print(float f){cout void print(const char *c){cout protected:
private:
int data;
};
int main(void)
{
printData pd; /* 声明一个对象pd */
pd.print(100);
pd.print(3.1415924626535f);
//const char *str = "Test."; // ERR:invalid conversion from ‘char*’ to ‘int’ [-fpermissive]
const char *str = "Test.";
pd.print(str);
cout
return 0;
}
编译、运行:
PS D:studycplusplusday6> make
g++ -o classOverload classOverload.cpp -g -Wall
PS D:studycplusplusday6> .classOverload.exe
int: 100
float: 3.14159
char: Test.
sizeof(printData): 4
C++ 中的运算符重载
可以重定义或重载大部分 C++ 内置的运算符。这样,就能使用自定义类型的运算符。
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator
和其后要重载的运算符符号构成的。
与其他函数一样,重载运算符有一个返回类型和一个参数列表。
Box operator+(const Box&);
实例2:
/*******************************************************************
* > File Name: classOverloadOperator.cpp
* > Create Time: 2021年09月 5日 20:10:39
******************************************************************/
#include
using namespace std;
class Box
{
public:
double getVolume(void)
{
return (length*width*height);
}
void setLength(double l)
{
length = l;
}
void setWidth(double w)
{
width = w;
}
void setHeight(double h)
{
height = h;
}
/* 重载+运算符,用于把两个box对象相加 */
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.width = this->width + b.width;
box.height = this->height + b.height;
return box;
}
protected:
private:
double length;
double width;
double height;
};
int main(void)
{
Box box1;
Box box2;
Box box3;
double volume = 0.0;
box1.setLength(2.0);
box1.setWidth(3.0);
box1.setHeight(4.0);
box2.setLength(3.0);
box2.setWidth(4.0);
box2.setHeight(5.0);
volume = box1.getVolume();
cout
volume = box2.getVolume();
cout
box3 = box1 + box2;
volume = box3.getVolume();
cout
return 0;
}
编译、运行:
PS D:studycplusplusday6> make
g++ -o classOverloadOperator classOverloadOperator.cpp -g -Wall
PS D:studycplusplusday6> .classOverloadOperator.exe
Volume of box1: 24
Volume of box2: 60
Volume of box3: 315
可重载运算符/不可重载运算符
下面是可重载的运算符列表:
双目算术运算符
|
+ (加),- (减),* (乘),/ (除),% (取模)
|
关系运算符
|
== (等于),!= (不等于), (小于),> (大于),(小于等于),>= (大于等于)
|
逻辑运算符
|
||(逻辑或),&& (逻辑与),! (逻辑非)
|
单目运算符
|
+ (正),- (负),* (指针),& (取地址)
|
自增自减运算符
|
++ (自增),-- (自减)
|
位运算符
|
| (按位或),& (按位与),~ (按位取反),^ (按位异或),, (左移),>> (右移)
|
赋值运算符
|
= , += , -= , *= , /= , % = , &= , |=, ^= , , >>=
|
空间申请与释放
|
new , delete , new[ ] , delete[]
|
其他运算符
|
()(函数调用),->(成员访问),,(逗号),[](下标)
|
下面是不可重载的运算符列表:
-
.
:成员访问运算符
-
.
*, ->
*:成员指针访问运算符
-
::
:域运算符
-
sizeof
:长度运算符
-
?:
:条件运算符
-
#
: 预处理符号
运算符重载实例
运算符重载 | C++ 一元运算符重载
一元运算符只对一个操作数进行操作,下面是一元运算符的实例:
- 递增运算符( ++ )和递减运算符( —
- 一元减运算符,即负号(
-
)
- 逻辑非运算符(
!
)
一元运算符通常出现在它们所操作的对象的左边,比如 !obj
、-obj
和 ++obj
,但有时它们也可以作为后缀,比如 obj++
或 obj--
。
实例3:
/*******************************************************************
* > File Name: classOverloadUnaryOperator.cpp
* > Create Time: 2021年09月 5日 22:07:55
******************************************************************/
#include
using namespace std;
class Distance
{
public:
Distance(){ /* 构造函数 */
cout feet = 0;
inches = 0;
cout }
Distance(int f, int i){ /* 构造函数的重载 */
cout feet = f;
inches = i;
cout }
void displayDistance(){
cout }
// 重载负运算符(-)
Distance operator-(){
feet = -feet;
inches = -inches;
return Distance(feet, inches);
}
protected:
private:
int feet; // 0到无穷
int inches; // 0到12
};
int main(void)
{
Distance D1(11, 10);
Distance D2(-5, 11);
-D1;
D1.displayDistance();
-D2;
D2.displayDistance();
return 0;
}
编译、运行:
PS D:studycplusplusday6> make
g++ -o classOverloadUnaryOperator classOverloadUnaryOperator.cpp -g -Wall
PS D:studycplusplusday6> .classOverloadUnaryOperator.exe
Calling constructor 2.
2.F: 11 I: 10
Calling constructor 2.
2.F: -5 I: 11
Calling constructor 2.
2.F: -11 I: -10
F: -11 I: -10
Calling constructor 2.
2.F: 5 I: -11
F: 5 I: -11
运算符重载 | C++ 二元运算符重载
二元运算符需要两个参数。
平常使用的加运算符( +
)、减运算符( -
)、乘运算符( *
)和除运算符( /
)都属于二元运算符。
实例4:
/*******************************************************************
* > File Name: classOverloadBinaryOperator.cpp
* > Create Time: 2021年09月 5日 22:41:10
******************************************************************/
#include
using namespace std;
class Box{
double length;
double width;
double height;
public:
double getVoluem(void)
{
return length*width*height;
}
void setLength(double l)
{
length = l;
}
void setWidth(double w)
{
width = w;
}
void setHeight(double h)
{
height = h;
}
// 重载+运算符,用于把两个Box对象相加
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.width = this->width + b.width;
box.height = this->height + b.height;
return box;
}
};
int main(void)
{
Box box1; // 声明对象box1
Box box2;
Box box3;
double volume = 0.0;
box1.setLength(2.0);
box1.setWidth(3.0);
box1.setHeight(4.0);
box2.setLength(3.0);
box2.setWidth(4.0);
box2.setHeight(5.0);
volume = box1.getVoluem(); // 获取box1的体积
cout
volume = box2.getVoluem(); // 获取box2的体积
cout
box3 = box1 + box2; // 两个对象相加得到box3
volume = box3.getVoluem(); // 获取box3的体积
cout
return 0;
}
编译、运行:
PS D:studycplusplusday6> make
g++ -o classOverloadBinaryOperator classOverloadBinaryOperator.cpp -g -Wall
PS D:studycplusplusday6> .classOverloadBinaryOperator.exe
Volume of box1: 24
Volume of box2: 60
Volume of box3: 315
运算符重载 | C++关系运算符重载
C++ 语言支持各种关系运算符( 、 = 、 == 等等),它们可用于比较 C++ 内置的数据类型。
可以重载任何一个关系运算符,重载后的关系运算符可用于比较类的对象。
实例5:
/*******************************************************************
* > File Name: classOverloadRelationOperator.cpp
* > Create Time: 2021年09月 6日 8:50:28
******************************************************************/
#include
using namespace std;
class Distance{
public:
int feet; // 0~无穷
int inches; // 0~12
Distance(){
cout feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
void displayDistance(void){
cout }
/* 重载运算符- */
Distance operator-(){
feet = -feet;
inches = - inches;
return Distance(feet, inches);
}
/* 重载运算法 bool operator if(feet {
return true;
}
if (feet == d.feet && inches {
return true;
}
return false;
}
protected:
private:
};
int main(void)
{
Distance D1(11, 10);
Distance D2(5, 11);
if(D1 {
cout }
else
{
cout }
return 0;
}
编译、运行:
PS E:fly-prjcplusplusday7> make
g++ -o classOverloadRelationOperator classOverloadRelationOperator.cpp -g -Wall
PS E:fly-prjcplusplusday7> .classOverloadRelationOperator.exe
D2 is less than D1
运算符重载 | C++ 输入/输出运算符重载
C++ 能够使用流提取运算符 >> 和流插入运算符 您可以重载流提取运算符和流插入运算符来操作对象等用户自定义的数据类型。
在这里,有一点很重要,我们需要把运算符重载函数声明为类的友元函数,这样我们就能不用创建对象而直接调用函数。
实例6:
/*******************************************************************
* > File Name: classOverloadIOputOperator.cpp
* > Create Time: 2021年09月 6日 9:07:42
******************************************************************/
#include
using namespace std;
class Distance{
private:
int feet;
int inches;
public:
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
friend ostream &operator {
output return output;
}
friend istream &operator>>(istream &input, Distance &D)
{
input >> D.feet >> D.inches;
return input;
}
};
int main(void)
{
Distance D1(11, 10);
Distance D2(5, 11);
Distance D3;
cout cin >> D3;
cout cout cout
return 0;
}
编译、运行:
PS E:fly-prjcplusplusday7> make
g++ -o classOverloadIOputOperator classOverloadIOputOperator.cpp -g -Wall
PS E:fly-prjcplusplusday7> .classOverloadIOputOperator.exe
Enter the value of object:
12
13
First Distance: F: 11 I:10
Second Distance: F: 5 I:11
Third Distance: F: 12 I:13
笔记
习惯上人们是使用 cin>>
和 cout
的,得使用友元函数来重载运算符,如果使用成员函数来重载会出现 d1
; 这种不自然的代码。
下面这个实例展示了如果运用成员函数来重载会出现的情况**d1**
实例7:
/*******************************************************************
* > File Name: classOverloadIOputOperator1.cpp
* > Create Time: 2021年09月 6日 9:35:10
******************************************************************/
#include
using namespace std;
class Distance
{
private:
int feet;
int inches;
public:
Distance(){
cout feet = 0;
inches = 0;
}
Distance(int f, int i){
cout feet = f;
inches = i;
}
~Distance(){
cout }
ostream& operator os return os;
}
};
int main(void)
{
Distance d1(20, 18);
d1 return 0;
}
编译、运行:
PS E:fly-prjcplusplusday7> make
g++ -o classOverloadIOputOperator1 classOverloadIOputOperator1.cpp -g -Wall
PS E:fly-prjcplusplusday7> .classOverloadIOputOperator1.exe
calling constructor 2.
F: 20
I: 18
calling destructor.
如果是 d1 的话,相当于调用了一次:
跟重载 + 运算符的调用没有什么区别,都是属于类变量的操作:
因为最后返回的还是 os,所以可以循环使用,也就是写成:
是没有问题的。
如果是 cout
; 就需要在类的外部定义:
这个时候调用,就相当于在整个全局声明了一个重载运算符。
调用这个重载运算符,就相当于调用了一个函数:
ostream& function_name (ostream &output, const Distance D)
{
/// output = cout
output return output;
}
同样地,因为返回的是 output, 所以还是可以循环调用的。
运算符重载 | C++ ++ 和 – 运算符重载
递增运算符( ++ )和递减运算符( – )是 C++ 语言中两个重要的一元运算符。
实例8:
/*******************************************************************
* > File Name: classOverloadAddOperator.cpp
* > Create Time: 2021年09月 6日 9:57:00
******************************************************************/
#include
using namespace std;
class Time{
private:
int hours; /* 0~23 */
int minutes; /* 0~59 */
protected:
public:
Time(){
cout hours = 0;
minutes = 0;
}
Time(int h, int m){
cout hours = h;
minutes = m;
}
void displayTime(){
cout }
// 重载前缀递增运算符( ++ )
Time operator++(){
++minutes;
if(minutes >= 60){
++hours;
minutes -= 60;
}
return Time(hours, minutes);
}
// 重载后缀递增运算符( ++ )
// int 在 括号内是为了向编译器说明这是一个后缀形式,而不是表示整数。
// 前缀形式重载调用 Check operator ++ () ,后缀形式重载调用 operator ++ (int)。
Time operator++(int){
Time T(hours, minutes);
++minutes;
if(minutes >= 60){
++hours;
minutes -= 60;
}
return T;
}
};
int main(void)
{
Time t1(11, 59);
Time t2(10, 40);
t1++;
t1.displayTime();
t1++;
t1.displayTime();
++t2;
t2.displayTime();
++t2;
t2.displayTime();
return 0;
}
编译、运行:
PS E:fly-prjcplusplusday7> make
g++ -o classOverloadAddOperator classOverloadAddOperator.cpp -g -Wall
PS E:fly-prjcplusplusday7> .classOverloadAddOperator.exe
calling constructor2.
calling constructor2.
calling constructor2.
H: 12 M:0
calling constructor2.
H: 12 M:1
calling constructor2.
H: 10 M:41
calling constructor2.
H: 10 M:42
实例9 (++ 重载):
/*******************************************************************
* > File Name: classOverloadAddOperator1.cpp
* > Create Time: 2021年09月 6日 11:57:22
******************************************************************/
#include
using namespace std;
class Check{
private:
int i;
public:
Check():i(0){cout Check operator++(){
Check temp;
temp.i = ++i;
return temp;
}
Check operator++(int){
Check temp;
temp.i = i ++;
return temp;
}
void display(){
cout }
};
int main(void)
{
Check obj1;
Check obj2;
obj1.display();
obj1.display();
obj1 = ++ obj2;
obj2.display();
obj1.display();
obj1 = obj2 ++;
obj2.display();
obj1.display();
return 0;
}
编译、运行:
PS E:fly-prjcplusplusday7> make
g++ -o classOverloadAddOperator1 classOverloadAddOperator1.cpp -g -Wall
PS E:fly-prjcplusplusday7> .classOverloadAddOperator1.exe
calling constructor.
calling constructor.
i: 0
i: 0
calling constructor.
i: 1
i: 1
calling constructor.
i: 2
i: 1
实例10(–重载):
/*******************************************************************
* > File Name: classOverloadReduceOperator.cpp
* > Create Time: 2021年09月 6日 13:47:15
******************************************************************/
#include
using namespace std;
class Check{
private:
int i;
public:
Check():i(3){cout Check operator--(){
Check temp;
temp.i = --i;
return temp;
}
Check operator--(int){
Check temp;
temp.i = i --;
return temp;
}
void display(){
cout }
};
int main(void)
{
Check obj1;
Check obj2;
obj1.display();
obj1.display();
obj1 = -- obj2;
obj2.display();
obj1.display();
obj1 = obj2 --;
obj2.display();
obj1.display();
return 0;
}
编译、运行:
PS E:fly-prjcplusplusday7> make
g++ -o classOverloadReduceOperator classOverloadReduceOperator.cpp -g -Wall
PS E:fly-prjcplusplusday7> .classOverloadReduceOperator.exe
calling constructor.
calling constructor.
i: 3
i: 3
calling constructor.
i: 2
i: 2
calling constructor.
i: 1
i: 2
运算符重载 | C++ 赋值运算符重载
就像其他运算符一样,您可以重载赋值运算符( = ),用于创建一个对象,比如拷贝构造函数。
实例11:
/*******************************************************************
* > File Name: classOverloadOperator1.cpp
* > Create Time: 2021年09月 6日 13:52:36
******************************************************************/
#include
using namespace std;
class Distance
{
private:
int feet;
int inches;
public:
Distance()
{
cout feet = 0;
inches = 0;
}
Distance(int f, int i)
{
cout feet = f;
inches = i;
}
void displayDistance()
{
cout }
void operator=(const Distance& D)
{
feet = D.feet;
inches = D.inches;
}
};
int main(void)
{
Distance d1(11, 10);
Distance d2(5, 11);
cout d1.displayDistance();
cout d2.displayDistance();
d1 = d2;
cout d1.displayDistance();
return 0;
}
编译、运行:
PS E:fly-prjcplusplusday7> make
g++ -o classOverloadOperator1 classOverloadOperator1.cpp -g -Wall
PS E:fly-prjcplusplusday7> .classOverloadOperator1.exe
calling construtor,f = 11 i = 10.
calling construtor,f = 5 i = 11.
First Box
F: 11 I: 10
Second Box
F: 5 I: 11
First Box
F: 5 I: 11
运算符重载 | C++ 函数调用运算符 () 重载
函数调用运算符 () 可以被重载用于类的对象。当重载 () 时,您不是创造了一种新的调用函数的方式,相反地,这是创建一个可以传递任意数目参数的运算符函数。
实例12:
/*******************************************************************
* > File Name: classOverloadOperator2.cpp
* > Create Time: 2021年09月 6日 14:17:18
******************************************************************/
#include
using namespace std;
class Distance
{
private:
int feet;
int inches;
public:
Distance()
{
feet = 0;
inches = 0;
}
Distance(int f, int i)
{
feet = f;
inches = i;
}
void displayDistance(void)
{
cout cout }
Distance operator()(int a, int b, int c)
{
Distance D;
D.feet = a + c + 10;
D.inches = b + c + 100;
return D;
}
};
int main(void)
{
Distance d1(10, 10);
Distance d2;
d1.displayDistance();
d2 = d1(10, 10, 10);
d2.displayDistance();
return 0;
}
编译、运行:
PS E:fly-prjcplusplusday7> make
g++ -o classOverloadOperator2 classOverloadOperator2.cpp -g -Wall
PS E:fly-prjcplusplusday7> .classOverloadOperator2.exe
F = 10
I = 10
F = 30
I = 120
运算符重载 | C++ 下标运算符 [] 重载
下标操作符 [] 通常用于访问数组元素。重载该运算符用于增强操作 C++ 数组的功能。
实例13:
/*******************************************************************
* > File Name: classOverloadOperator3.cpp
* > Create Time: 2021年09月 6日 14:34:46
******************************************************************/
#include
using namespace std;
const int SIZE = 10;
class Safearay
{
private:
int arr[SIZE];
public:
Safearay()
{
register int i; // 意味着变量可能存储在寄存器中,用于快速访问,不能使用“&”运算
for(i = 0; i {
arr[i] = i;
}
}
int& operator[](int i) /* 重载[] */
{
if(i > SIZE)
{
cout SIZE" return arr[0];
}
return arr[i];
}
};
int main(void)
{
Safearay A;
cout cout cout return 0;
}
编译、运行:
PS E:fly-prjcplusplusday7> make
g++ -o classOverloadOperator3 classOverloadOperator3.cpp -g -Wall
classOverloadOperator3.cpp: 在构造函数‘Safearay::Safearay()’中:
classOverloadOperator3.cpp:19:22: 警告:ISO C++17 does not allow ‘register’ storage class specifier [-Wregister]
19 | register int i; // 意味着变量可能存储在寄存器中,用于快速访问,不能使用“&”运算
| ^
PS E:fly-prjcplusplusday7> .classOverloadOperator3.exe
The value of arr[ 2]: 2
The value of arr[5]: 5
The value of arr[12]: ERR: i > SIZE
0
运算符重载 | C++ 类成员访问运算符 -> 重载
类成员访问运算符( ->
)可以被重载,但它较为麻烦。它被定义用于为一个类赋予”指针”行为。运算符 ->
必须是一个成员函数。如果使用了 ->
运算符,返回类型必须是指针或者是类的对象。
运算符 ->
通常与指针引用运算符 *
结合使用,用于实现”智能指针”的功能。这些指针是行为与正常指针相似的对象,唯一不同的是,当您通过指针访问对象时,它们会执行其他的任务。比如,当指针销毁时,或者当指针指向另一个对象时,会自动删除对象。
间接引用运算符 ->
可被定义为一个一元后缀运算符。也就是说,给出一个类:
class Ptr{
//...
X * operator->();
};
类 **Ptr**
的对象可用于访问类 X
void f(Ptr p )
{
p->m = 10 ; // (p.operator->())->m = 10
}
语句 p->m
被解释为 (p.operator->())->m
。同样地,下面的实例演示了如何重载类成员访问运算符 ->
。
实例14:
/*******************************************************************
* > File Name: classOverloadOperator1.cpp
* > Create Time: Mon Sep 6 15:21:33 2021
******************************************************************/
#include
#include
using namespace std;
// 假设一个实际的类
class Obj {
/*static*/ int i, j;
public:
void f() const { cout void g() const { cout };
// 静态成员定义
int Obj::i = 10;
int Obj::j = 12;
// 为上面的类实现一个容器
class ObjContainer {
vector a;
public:
void add(Obj* obj)
{
a.push_back(obj); // 调用向量的标准方法
}
friend class SmartPointer;
};
// 实现智能指针,用于访问类 Obj 的成员
class SmartPointer {
ObjContainer oc;
int index;
public:
SmartPointer(ObjContainer& objc)
{
oc = objc;
index = 0;
}
// 返回值表示列表结束
bool operator++() // 前缀版本
{
if(index >= oc.a.size() - 1) return false;
if(oc.a[++index] == 0) return false;
return true;
}
bool operator++(int) // 后缀版本
{
return operator++();
}
// 重载运算符 ->
Obj* operator->() const
{
if(!oc.a[index])
{
cout return (Obj*)0;
}
return oc.a[index];
}
};
int main() {
const int sz = 10;
Obj o[sz];
ObjContainer oc;
for(int i = 0; i {
oc.add(&o[i]);
}
SmartPointer sp(oc); // 创建一个迭代器
do {
sp->f(); // 智能指针调用
sp->g();
} while(sp++);
return 0;
}
编译、运行:
lanfeiy@yelanfei ~/workspace/cpp
$ make
g++ -o classOverloadOperator1 classOverloadOperator1.cpp
lanfeiy@yelanfei ~/workspace/cpp
$ ./classOverloadOperator1.exe
10
12
11
13
12
14
13
15
14
16
15
17
16
18
17
19
18
20
19
21
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.e1idc.net