目录
一、函数重载
函数重载(Overloading)是C++中一个非常重要的特性,它允许在同一个作用域内定义多个同名函数,只要它们的参数列表不同即可。
基本概念
在 C++ 里,函数重载指的是在同一个作用域内,能够存在一组函数名相同但参数列表不同的函数。这里所说的参数列表不同,包括参数类型、参数数量或者参数顺序的差异。
当调用这些重载函数时,编译器会依据传入的实参情况,结合实参的类型和数量,来确定具体调用哪一个函数。比如,若调用时传入的实参类型和数量与某个重载函数的参数列表匹配,编译器就会调用该函数。
函数重载的条件
函数名必须相同
参数列表必须不同(如参数类型、参数数量或参数顺序不同)
返回类型可以相同也可以不同(仅返回类型不同不能构成重载)
编程示例
#include <iostream>
// 使用标准命名空间,这样就可以直接使用标准库中的对象和函数,无需加 std:: 前缀
using namespace std;
// 定义一个名为 func 的类,该类中包含了多个重载的 print 函数
class func
{
public:
// 声明一个打印整数的函数,接受一个 int 类型的参数
void print(int idata1);
// 声明一个打印两个整数并计算它们之和的函数,接受两个 int 类型的参数
void print(int idata1, int idata2);
// 声明一个打印双精度浮点数的函数,接受一个 double 类型的参数
void print(double ddata1);
// 声明一个打印字符串的函数,接受一个字符数组(C 风格字符串)作为参数
void print(char c[]);
};
// 类外定义 print 函数,实现打印一个整数的功能
void func::print(int idata1)
{
// 输出传入的整数
cout << "idata1:" << idata1 << endl;
}
// 类外定义 print 函数,实现打印两个整数并计算它们之和的功能
void func::print(int idata1, int idata2)
{
// 输出传入的两个整数以及它们的和
cout << "idata1:" << idata1 << ",idata2:" << idata2 << ",idata1 + idata2 = " << idata1 + idata2 << endl;
}
// 类外定义 print 函数,实现打印一个双精度浮点数的功能
void func::print(double ddata1)
{
// 输出传入的双精度浮点数
cout << "ddata1:" << ddata1 << endl;
}
// 类外定义 print 函数,实现打印一个字符串的功能
void func::print(char c[])
{
// 输出传入的字符串
cout << "字符串:" << c << endl;
}
int main()
{
// 创建 func 类的一个对象 f1
func f1;
// 定义一个字符数组(C 风格字符串)并初始化为 "hello world"
char cdata[] = "hello world";
// 调用 print 函数,传入一个整数,此时会调用接受一个 int 参数的 print 函数
f1.print(10);
// 调用 print 函数,传入两个整数,此时会调用接受两个 int 参数的 print 函数
f1.print(10,20);
// 调用 print 函数,传入一个双精度浮点数,此时会调用接受一个 double 参数的 print 函数
f1.print(3.14);
// 调用 print 函数,传入一个字符数组,此时会调用接受一个字符数组参数的 print 函数
f1.print(cdata);
return 0;
}
代码讲解
- 类的定义:
func
类中声明了四个重载的print
函数,这些函数的名称相同,但参数列表不同。这是 C++ 函数重载的典型应用,通过函数重载可以使用相同的函数名来处理不同类型或数量的参数。
- 函数定义:
- 在类外对这四个
print
函数进行了定义,每个函数都有不同的实现逻辑,分别用于处理不同类型的输入。
- 在类外对这四个
main
函数:- 创建了
func
类的一个对象f1
。 - 定义了一个字符数组
cdata
并初始化为"hello world"
。 - 多次调用
f1
的print
函数,每次传入不同类型或数量的参数。编译器会根据传入的实参自动选择合适的重载函数进行调用。例如,传入一个整数时,会调用接受一个int
参数的print
函数;传入两个整数时,会调用接受两个int
参数的print
函数,以此类推。
- 创建了
函数重载的注意事项
返回类型不同不构成重载
int func(int a); // 正确
double func(int a); // 错误,仅返回类型不同
默认参数可能导致重载歧义
void func(int a);
void func(int a, int b = 0); // (默认b=0)
func(10); // 编译器无法确定调用哪个函数
const修饰符可以构成重载
对于指针或引用参数,const可以构成重载
对于值参数,const不能构成重载
// 可以构成重载
void func(int &a);
void func(const int &a);
// 不能构成重载
void func(int a);
void func(const int a); // 重复声明
函数重载与作用域
在不同作用域中的同名函数不构成重载
派生类中的同名函数会隐藏基类中的同名函数
二、运算符重载
什么是运算符重载?
运算符重载:赋予运算符具有操作自定义类型数据功能
运算符重载的实质是什么?
运算符重载的实质本身就是函数调用
运算符重载函数的写法
函数返回值类型 函数名(函数参数)
- 函数返回值的类型 :运算完成后的值决定的
- 函数名 :operator 加上重载运算符组成函数名,例如:operator+
- 参数列表 :看运算符的操作数,具体参数个数需要看函数的形式(成员函数或友元函数)
- 函数体 :写运算符具体想要的操作
运算符重载的基本语法
返回类型 operator运算符(参数列表) {
// 实现代码
}
可重载的运算符列表
可以重载的运算符:
+ - * / % ^ & | ~ ! = < >
+= -= *= /= %= ^= &= |=
<< >> >>= <<= == != <= >=
&& || ++ -- , ->* -> () []
new new[] delete delete[]
不能重载的运算符:
. .* :: ?: sizeof typeid
基本原则
1. 不可以创建新的运算符:只能重载已经存在的运算符。
2. 至少有一个操作数是用户定义的类型:不能重载两个基本类型的运算符。
3. 不能更改运算符的优先级:重载的运算符保持其原有的优先级和结合性。
编程示例
这个示例创建了三个对象:p1、p2、p3;分别对 p1、p2 这两个对象的成员变量赋值,p3 的值等于p1 + p2。运算符 + 只能对基本数据类型进行计算,不能对自定义类型进行计算。所以我们需要重载运算符 + ,才能进行对象 p1 和 p2 进行计算,将 p1 + p2 的运算结果存储在对象 p3。
#include <iostream>
using namespace std;
// 定义一个名为coord的类,表示二维坐标点
class coord
{
public:
int x; // x坐标
int y; // y坐标
// 声明重载大于运算符(>)的成员函数
bool operator>(coord data);
};
// 实现重载的大于运算符
// 比较规则:比较两个坐标点的x和y之和
bool coord::operator>(coord data)
{
return ((x + y) > (data.x + data.y));
}
int main()
{
// 创建第一个坐标点p1
coord p1;
p1.x = 9; // 设置p1的x坐标为9
p1.y = 6; // 设置p1的y坐标为6
// 创建第二个坐标点p2
coord p2;
p2.x = 5; // 设置p2的x坐标为5
p2.y = 6; // 设置p2的y坐标为6
// 类成员函数重载,参数个数等于操作数减一
// 使用重载的>运算符比较两个坐标点,实际比较的是(9+6)和(5+6),即15和11
if( p1 > p2 ) // p1 > p2(隐式调用) 等价于 p1.operator>(p2)(显示调用)
{
cout << "p1大于p2" << endl; // 会输出这个结果
}
else
{
cout << "p2大于p1" << endl;
}
return 0;
}
代码解释
上面代码的重载函数是成员函数形式,当运算符重载作为成员函数时,它已经有一个隐含的参数——调用对象本身(this
指针)。所以:
调用对象:运算符左侧的对象(
p1
)是调用者,通过this
指针隐式传递参数对象:运算符右侧的对象(
p2
)作为显式参数传递
注意事项
- 一致性:重载的运算符应与其原始意图和常见用法保持一致。例如, + 运算符通常应该实现加法,而不是其他意外的操作。
- 复杂性:过度使用运算符重载可能导致代码难以理解和维护。确保它们的使用直观且合理。 运算符重载是C++中提高代码可读性和表达力的强大工具,但需要谨慎使用,以保证代码的清晰性和维护性。