七、函数重载与默认参数(Function Overloading Default Arguments)
七、函数重载与默认参数(Function Overloading & Default Arguments)
7.1 名称修饰(More name decoration)
-
函数重载(Function Overloading): 相同的函数名,参数类型 或数量不同
-
注意点:
-
返回类型 不参与重载决议。
int add(int,int); void add(int,int);//错误:重定义
-
参数名不影响重载
int add(int x, int y) { } void add(int a, int b) { } // 错误:重新定义(redefinition)
-
-
示例
//The number of arguments are different int min(int a,int b){return a<b ? a:b; }int min(int a,int b,int c){int t = min(a,b);return min(t,c); }void main(){cout << min(-2,8,0) << endl;cout << min(0,8) << endl; }
7.2 函数重载实例
Stash3.h
//C07:Stash3.h
#ifndef STASH3_H
#define STASH3_H
class Stash{int size;// Size of each spaceint quantity;// Number of storage spacesint next;// Next empty spaceunsigned char* storage;// Dynamically allocated array of bytesvoid inflate(int increase);
public:Stash(int size);//Zero quantityStash(int size,int initQuantity);~Stash();int add(void* element);void* fetch(int index);int count();
};
#endif STASH3_H
函数重载:
Stash(int size);//Zero quantity Stash(int size,int initQuantity);
Stash3.cpp
//C07:Stash3.cpp
#include "Stash3.h"
#include <iostream>
using namespace std;
const int increment = 100;
Stash::Stash(int sz){size = sz;quantity = 0;next = 0;storage = nullptr;
}Stash::Stash(int sz,int iniQuantity){size = sz;quantity = 0;next = 0;storage = 0;inflate(initQuantity);
}
…………
7.3 联合体(unions)
struct
默认 public ,class
默认 private 。除此之外,二者几乎一样。union
可包含构造函数、析构函数、成员函数。union
和class
区别是:内存存储方式不同 ,union
成员共用内存。union
不能作为基类继承。
7.4 默认参数(Default arguments)
概述
- 默认参数 是在函数声明中给定的一个值,当你在调用函数时没有提供对应的参数值,编译器会自动填入这个默认值 。
- 就像函数重载一样,默认参数 允许你在不同情况下使用相同的函数名 .
- 和函数重载不同之处在于,是用 默认参数 时,是编译器在替你填补参数值 ,而不是你手动写出多个函数版本。
例子
-
无默认参数
class Date{int year,month,day; public:Date(){year = 0;month = 0;day = 0;}Date(int y){year = y;month = 0;day = 0;}Date(int y,int m){year = y;month = m;day = 0;}Date(int y,int m,int d){year = y;month = m;day = d;} };void main(){Date a;Date b(2004);Date c(2004,1);Date d(2025,4,25); }
-
含默认参数
class Date{int year,month,day; public:Date(int y = 0,int m = 0,int d =0){year = y;month = m;day = d;} };void main(){Date a;Date b(2004);Date c(2004,1);Date d(2025,4,25); }
-
函数含默认参数,声明与定义
定义
#include <iostream> using namespace std; void fun(int a = 1,int b = 3,int c = 5)//definition {cout << a << "." << b << "." << c << endl; }//declaration void main(){fun();//1,3,5fun(1);fun(1,3);fun(1,3,5); }
声明
#include <iostream> using namespace std; void fun(int a = 1,int b = 3,int c = 5);//declaration void main(){fun();//1,3,5fun(1);fun(1,3);fun(1,3,5); } void fun(int a,int b,int c){cout << a << "." << b << "." << c << endl; }
默认参数只能写一次,写在函数声明 或定义 中都行,但不能写两次
规则
-
默认参数只能从右往左提供,不能从中间跳过
int f(int, int = 0, char* = 0); // OK int g(int = 0, int, char* = 0); // error
原因:
-
默认参数的作用,是在调用函数时编译器自动补全你没写的参数。
假设这样写
void f(int a = 1, int b, int c = 3); // ❌ 错误!void main(){f(10); }
编译器会不知道
10
是传给a
,b
没有值?10
是传给b
,a
默认值1
吗?
-
C++编译器从右往左补参数
编译器在补默认参数时,是又右边开始一个个往左补的。所以必须保证:
- 右边有默认参数,编译器才能往左跳。
- 如果右边没有默认值而左边有,它就不知道从哪里开始补了。
-
-
默认参数可以是字面值 、常量 或表达式
int f(); void delay(int k,int time = f());
-
默认参数在同一作用域中只能定义一次:默认参数只能写一次,写在函数声明 或定义 中都行,但不能写两次 。
void fun(int x = 7); void fun(int x = 8); // error 错误:重复定义
占位参数(Placeholder arguments)
-
在函数声明中,参数可以不写参数名:
void f1(int x,int = 0,float = 1.1);
-
在函数定义中,也可以不写所有参数名:
void f2(int x,int,float flt){}
-
在上面这个函数体中,
x
和flt
是可以使用的,但中间那个int
参数不能用,因为它没有名字(是匿名占位参数)。但是调用函数时还是必须给出这个参数的值。f2(1, 2, 3.0); //调用时必须写3个实参
-
一般用于库开发者对外提供接口声明时的头文件,或仅作函数原型说明的场景。比如
// 在头文件中: void logEvent(int, const char*);// 在 .cpp 文件中: void logEvent(int level, const char* msg) {cout << level << ": " << msg << endl; }
7.5 选择重载还是默认参数
- 二者都可以提升函数调用灵活性,选择依据:
- 效率
- 接口设计清晰度(可复用性)
- 如果你选择的方法能让类更简单使用和复用,那么就成功了
重载
//add.h
int add(int a,int b);//add.cpp
#include "add.h"
int add(int a,int b){return (a+b);
}
int add(int a,int b,int c){return (a+b+c);
}
//app_1.cpp
#include "add.h"
void main(){add(2,3);add(2,3,4);
}
默认参数
//add.h
int add(int a,int b,int c = 0);//add.cpp
#include "add.h"
int add(int a,int b,int c){return (a+b+c);
}//app_2.cpp
#include "add.h"
void main(){add(2,3);add(2,3,4);
}
7.6 总结
- 函数重载:使用相同函数名,处理不同类型或数量参数。
- 默认参数:简化函数调用,提升接口友好性。