C++中的重载(Overloading)是指在同一作用域中允许多个同名函数或运算符通过不同的参数列表(函数重载)或操作数(运算符重载)进行定义和区分。重载是C++语言的一项重要特性,使得程序的可读性和灵活性大大增强。
C++ 中有两种重载方式:
- 函数重载(Function Overloading)
- 运算符重载(Operator Overloading)
1. 函数重载(Function Overloading)
函数重载允许在同一个作用域中定义多个同名函数,只要它们的参数类型、参数数量或参数顺序不同即可。编译器通过参数列表来区分调用的是哪一个重载函数。
1.1 函数重载的规则
- 参数类型不同:不同的参数类型可以重载同一个函数。例如,一个可以接受
int
,另一个可以接受double
。 - 参数数量不同:同一个函数名可以有不同数量的参数。
- 参数顺序不同:即使参数类型相同,只要参数的顺序不同,函数也可以被重载。
函数的返回类型不能作为重载的依据,编译器仅通过参数列表来区分重载的函数。
#include <iostream>
// 重载的函数,参数类型不同
void display(int i) {
std::cout << "Integer: " << i << std::endl;
}
void display(double d) {
std::cout << "Double: " << d << std::endl;
}
// 重载的函数,参数数量不同
void display(int i, double d) {
std::cout << "Integer: " << i << ", Double: " << d << std::endl;
}
int main() {
display(5); // 调用 display(int)
display(5.5); // 调用 display(double)
display(5, 5.5); // 调用 display(int, double)
return 0;
}
1.3 函数重载的好处
- 提高可读性:同一个功能可以使用相同的函数名,程序员不用记住不同的函数名,只需传入合适的参数类型或数量,编译器就能自动选择正确的函数。
- 提高灵活性:通过提供不同类型的输入,可以扩展函数的使用范围而无需修改原有函数。
2. 运算符重载(Operator Overloading)
C++允许重载内置运算符,使得自定义类型(如类对象)能够像内置类型一样使用运算符进行操作。运算符重载的语法使用 operator
关键字来定义。
2.1 运算符重载的基本规则
- 必须至少有一个操作数是用户定义的类型(如类或枚举)。不能为内置类型(如
int
或float
)重载运算符。 - 运算符重载的优先级和结合性不能改变,运算符重载仅仅是修改运算符的行为。
- 某些运算符不能重载,例如:
::
(作用域解析符).
(成员访问符).*
(成员指针访问符)?:
(条件运算符)
2.2 运算符重载示例
以重载 +
和 ==
运算符为例,为一个自定义的 Complex
类重载这两个运算符,使其能够处理复数的加法和比较。
#include <iostream>
class Complex {
private:
double real, imag;
public:
// 构造函数
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 重载加法运算符
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// 重载等于运算符
bool operator==(const Complex& other) const {
return (real == other.real && imag == other.imag);
}
// 显示复数
void display() const {
std::cout << real << " + " << imag << "i" << std::endl;
}
};
int main() {
Complex c1(1.0, 2.0), c2(3.0, 4.0);
Complex c3 = c1 + c2; // 使用重载的 + 运算符
c3.display();
if (c1 == c2) { // 使用重载的 == 运算符
std::cout << "c1 and c2 are equal" << std::endl;
} else {
std::cout << "c1 and c2 are not equal" << std::endl;
}
return 0;
}
2.3 常见运算符的重载
- 算术运算符:如
+
,-
,*
,/
等可以重载为处理对象的运算。 - 比较运算符:如
==
,!=
,<
,>
等可以重载为对象的比较。 - 赋值运算符:
=
可以重载来定义对象的赋值行为。 - 流插入和提取运算符:
<<
和>>
可以重载用于类对象的输入和输出操作。
2.4 一元和二元运算符重载
class Counter {
private:
int count;
public:
Counter() : count(0) {}
// 前置递增
Counter& operator++() {
++count;
return *this;
}
// 后置递增
Counter operator++(int) {
Counter temp = *this;
++count;
return temp;
}
void display() const {
std::cout << "Count: " << count << std::endl;
}
};
int main() {
Counter c;
++c; // 前置递增
c++; // 后置递增
c.display();
return 0;
}
运算符可以分为一元运算符和二元运算符:
- 一元运算符 只对一个操作数进行操作,比如
++
,--
,!
等。 - 二元运算符 需要两个操作数,比如
+
,-
,*
,/
等。
2.5 运算符重载的成员函数和非成员函数
-
成员函数重载:运算符作为类的成员函数时,左操作数是隐式对象(
this
)。 -
非成员函数重载:当左操作数不是该类的对象时,必须将运算符重载为全局函数或友元函数。例如,流插入运算符
<<
通常重载为非成员函数。
#include <iostream>
class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 重载输出运算符
friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << c.real << " + " << c.imag << "i";
return os;
}
};
int main() {
Complex c(3.0, 4.0);
std::cout << "Complex number: " << c << std::endl;
return 0;
}
3. 函数重载和运算符重载的区别
- 函数重载是通过定义同名但不同参数列表的函数来实现的,而运算符重载是通过为特定运算符定义自定义行为来实现的。
- 运算符重载的优先级和结合性无法改变,而函数重载没有这个限制。
总结
- 函数重载 提供了在同一作用域中定义多个同名函数的灵活性,允许根据不同的参数调用不同的函数版本。
- 运算符重载 使用户定义的类型对象能够像内置类型一样使用运算符进行操作,从而提高代码的可读性和简洁性。
四则运算符以及比较运算符重载示例:
#include <iostream>
class CBook {
private:
int m_iPage;
public:
CBook(int iPage) : m_iPage(iPage) {}
CBook operator+(const CBook& b) {
return CBook(m_iPage + b.m_iPage);
}
CBook operator-(const CBook& b) {
return CBook(m_iPage - b.m_iPage);
}
CBook operator*(const CBook& b) {
return CBook(m_iPage * b.m_iPage);
}
CBook operator/(const CBook& b) {
if (b.m_iPage == 0) {
std::cerr << "Error: Division by zero!" << std::endl;
return *this;
}
return CBook(m_iPage / b.m_iPage);
}
void display() const {
std::cout << m_iPage << std::endl;
}
bool operator>(const CBook& b) const {
return m_iPage > b.m_iPage;
}
bool operator<(const CBook& b) const {
return m_iPage < b.m_iPage;
}
bool operator==(const CBook& b) const {
return m_iPage == b.m_iPage;
}
};
int main() {
int n1{}, n2{};
std::cin >> n1 >> n2;
CBook book1(n1);
CBook book2(n2);
CBook book3(0);
book3 = book1 + book2;
book3.display();
book3 = book1 - book2;
book3.display();
book3 = book1 * book2;
book3.display();
book3 = book1 / book2;
book3.display();
if (book1 > book2) {
std::cout << "book1 > book2" << std::endl;
}
if (book1 < book2) {
std::cout << "book1 < book2" << std::endl;
}
if (book1 == book2) {
std::cout << "book1 == book2" << std::endl;
}
return 0;
}