欢迎光临
我们一直在努力

【20天学C++】Day 3: 函数增强

【20天学C++】Day 3: 函数增强

📅 学习时间:3-4小时
🎯 学习目标:掌握函数重载、默认参数、内联函数
💡 难度:★★☆☆☆


📝 Day 2 练习题答案

练习1答案:引用交换

#include <iostream>
using namespace std;

void swap(double &a, double &b) {
double temp = a;
a = b;
b = temp;
}

int main()
{
double x = 3.14, y = 2.71;
cout << "交换前: x=" << x << ", y=" << y << endl;
swap(x, y);
cout << "交换后: x=" << x << ", y=" << y << endl;
return 0;
}

练习2答案:数组翻倍

#include <iostream>
using namespace std;

int main()
{
int arr[] = {1, 2, 3, 4, 5};

for (int &x : arr) {
x *= 2;
}

for (int x : arr) {
cout << x << " ";
}
cout << endl; // 2 4 6 8 10
return 0;
}

练习3答案:统计大写字母

#include <iostream>
#include <string>
using namespace std;

int main()
{
string s = "Hello World";
int count = 0;

for (char c : s) {
if (c >= 'A' && c <= 'Z') {
count++;
}
}

cout << "大写字母个数: " << count << endl; // 2
return 0;
}

练习4答案:求最值

#include <iostream>
using namespace std;

void findMinMax(int arr[], int n, int &minVal, int &maxVal) {
minVal = maxVal = arr[0];
for (int i = 1; i < n; i++) {
if (arr[i] < minVal) minVal = arr[i];
if (arr[i] > maxVal) maxVal = arr[i];
}
}

int main()
{
int arr[] = {34, 78, 12, 95, 56};
int minVal, maxVal;
findMinMax(arr, 5, minVal, maxVal);
cout << "最小: " << minVal << ", 最大: " << maxVal << endl;
return 0;
}


1. 知识点概述

今天我们将学习C++函数的增强特性:

  • 函数重载(同名不同参)
  • 默认参数
  • 内联函数
  • 函数模板初探

2. 详细讲解

2.1 函数重载(Function Overloading)

什么是函数重载?

C语言:同名函数会冲突
int add(int a, int b);
double add(double a, double b); // ❌ 错误!名字冲突

C++:只要参数不同,可以同名
int add(int a, int b);
double add(double a, double b); // ✅ 允许!这叫函数重载

就像人一样:
– 我说"打开",你知道是打开门、打开窗、还是打开电视
– 根据上下文(参数)自动判断

函数重载示例:

#include <iostream>
using namespace std;

// 同名函数,参数不同
int add(int a, int b) {
cout << "int版本" << endl;
return a + b;
}

double add(double a, double b) {
cout << "double版本" << endl;
return a + b;
}

int add(int a, int b, int c) {
cout << "三参数版本" << endl;
return a + b + c;
}

int main()
{
cout << add(1, 2) << endl; // 调用int版本
cout << add(1.5, 2.5) << endl; // 调用double版本
cout << add(1, 2, 3) << endl; // 调用三参数版本

return 0;
}

重载的条件:

// ✅ 参数个数不同
void f(int a);
void f(int a, int b);

// ✅ 参数类型不同
void f(int a);
void f(double a);

// ✅ 参数顺序不同
void f(int a, double b);
void f(double a, int b);

// ❌ 仅返回值不同:不能重载!
int f(int a);
double f(int a); // 错误!无法区分

// ❌ 仅参数名不同:不能重载!
void f(int a);
void f(int b); // 错误!一样的函数

2.2 重载的原理

// 编译器会对函数名进行"改编"(Name Mangling)

void func(int a); // 编译后可能变成 _Z4funci
void func(double a); // 编译后可能变成 _Z4funcd
void func(int a, int b); // 编译后可能变成 _Z4funcii

// 这就是为什么参数不同可以重载
// 因为编译后的名字不同了

2.3 默认参数

#include <iostream>
using namespace std;

// 函数参数可以有默认值
void greet(string name = "游客") {
cout << "你好," << name << "!" << endl;
}

// 多个默认参数
void printInfo(string name, int age = 18, string city = "北京") {
cout << name << ", " << age << "岁, 来自" << city << endl;
}

int main()
{
greet(); // 使用默认值:你好,游客!
greet("张三"); // 你好,张三!

printInfo("李四"); // 李四, 18岁, 来自北京
printInfo("王五", 25); // 王五, 25岁, 来自北京
printInfo("赵六", 30, "上海"); // 赵六, 30岁, 来自上海

return 0;
}

默认参数的规则:

// 规则1:默认参数必须从右往左
void f(int a, int b = 10, int c = 20); // ✅ 正确
void f(int a = 10, int b, int c = 20); // ❌ 错误!中间有非默认参数

// 规则2:声明和定义只能写一处默认值(通常在声明中)
// 声明(头文件)
void func(int a, int b = 10);

// 定义(源文件)
void func(int a, int b) { // 不要再写默认值
// …
}

// 规则3:调用时可以省略有默认值的参数
void f(int a, int b = 10, int c = 20);
f(1); // a=1, b=10, c=20
f(1, 2); // a=1, b=2, c=20
f(1, 2, 3); // a=1, b=2, c=3

2.4 重载与默认参数的冲突

#include <iostream>
using namespace std;

// ⚠️ 小心!这会导致歧义
void f(int a) {
cout << "一个参数" << endl;
}

void f(int a, int b = 10) {
cout << "两个参数" << endl;
}

int main()
{
f(1, 2); // ✅ 明确调用两参数版本
// f(1); // ❌ 歧义!编译器不知道调哪个

return 0;
}

2.5 内联函数

什么是内联函数?

普通函数调用:
1. 跳转到函数地址
2. 执行函数代码
3. 返回调用处

内联函数:
编译时直接把函数代码"复制"到调用处
省去了跳转开销,但会增加代码体积

内联函数语法:

#include <iostream>
using namespace std;

// 内联函数:用inline关键字
inline int square(int x) {
return x * x;
}

inline int max(int a, int b) {
return a > b ? a : b;
}

int main()
{
int a = 5;
cout << square(a) << endl; // 编译时展开为:a * a
cout << max(3, 5) << endl; // 编译时展开为:3 > 5 ? 3 : 5

return 0;
}

内联函数 vs 宏:

// 宏定义(C风格)
#define SQUARE(x) ((x) * (x))

// 内联函数(C++风格)
inline int square(int x) {
return x * x;
}

int main()
{
int a = 5;

// 宏的陷阱
cout << SQUARE(a++) << endl; // a++被执行两次!

// 内联函数安全
a = 5;
cout << square(a++) << endl; // a++只执行一次

return 0;
}

/*
内联函数优势:
✅ 有类型检查
✅ 参数只计算一次
✅ 可以调试
*/

什么时候用内联函数?

适合内联的:
✅ 函数体很短(几行代码)
✅ 频繁调用的小函数
✅ 不含循环、递归

不适合内联的:
❌ 函数体很长(会导致代码膨胀)
❌ 含有循环
❌ 含有递归
❌ 虚函数(通常不会内联)

注意:inline只是建议,编译器可能忽略

2.6 constexpr函数(C++11)

#include <iostream>
using namespace std;

// constexpr函数:编译期计算
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n – 1);
}

constexpr int square(int x) {
return x * x;
}

int main()
{
// 编译期计算
constexpr int result = factorial(5); // 编译时就算好了
cout << "5! = " << result << endl;

// 可以用于数组大小
constexpr int size = square(3);
int arr[size]; // ✅ 合法,因为size是编译期常量

// 也可以运行时调用
int n = 4;
cout << factorial(n) << endl; // 运行时计算

return 0;
}


3. 代码示例

示例1:重载print函数

#include <iostream>
#include <string>
using namespace std;

void print(int n) {
cout << "整数: " << n << endl;
}

void print(double d) {
cout << "浮点数: " << d << endl;
}

void print(const string &s) {
cout << "字符串: " << s << endl;
}

void print(int arr[], int n) {
cout << "数组: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
}

int main()
{
print(42);
print(3.14);
print("Hello");

int arr[] = {1, 2, 3, 4, 5};
print(arr, 5);

return 0;
}

示例2:默认参数实现灵活函数

#include <iostream>
#include <string>
using namespace std;

// 格式化输出,支持多种样式
void printLine(char ch = '-', int count = 40, bool newline = true) {
for (int i = 0; i < count; i++) {
cout << ch;
}
if (newline) cout << endl;
}

// 创建问候语
string greet(string name = "朋友",
string greeting = "你好",
string punctuation = "!") {
return greeting + "," + name + punctuation;
}

int main()
{
printLine(); // —————————————-
printLine('='); // ========================================
printLine('*', 20); // ********************
printLine('#', 10, false); // ##########(不换行)
cout << endl;

cout << greet() << endl; // 你好,朋友!
cout << greet("张三") << endl; // 你好,张三!
cout << greet("李四", "早上好") << endl; // 早上好,李四!

return 0;
}

示例3:abs函数重载

#include <iostream>
using namespace std;

// 整数版本
inline int myabs(int n) {
return n >= 0 ? n : –n;
}

// 浮点数版本
inline double myabs(double n) {
return n >= 0 ? n : –n;
}

// 长整数版本
inline long long myabs(long long n) {
return n >= 0 ? n : –n;
}

int main()
{
cout << myabs(–10) << endl; // 10 (int)
cout << myabs(–3.14) << endl; // 3.14 (double)
cout << myabs(–100000000000LL) << endl; // (long long)

return 0;
}


4. 常见错误(踩坑指南)

错误1:仅返回值不同不能重载

// ❌ 错误!
int getValue();
double getValue(); // 返回值不同不能重载

// 编译器无法根据返回值确定调用哪个
// getValue(); 调哪个?

错误2:默认参数与重载冲突

void f(int a, int b = 10);
void f(int a);

// f(1); // ❌ 歧义!

错误3:默认参数位置错误

// ❌ 错误!默认参数必须从右往左
void f(int a = 1, int b, int c = 3);

// ✅ 正确
void f(int a, int b = 2, int c = 3);

错误4:重复写默认参数

// 声明
void f(int a, int b = 10);

// 定义 – 不要再写默认值!
void f(int a, int b = 10) { // ❌ 重复定义
// …
}

// ✅ 正确
void f(int a, int b) {
// …
}


5. 练习题目

练习1:重载max函数(难度:★★☆☆☆)

实现max函数的三个重载版本:两个int、两个double、三个int。

练习2:默认参数格式化输出(难度:★★☆☆☆)

实现函数printNumber(int n, int width = 8, char fill = ’ '),按指定宽度输出数字。

练习3:重载加法函数(难度:★★☆☆☆)

实现add函数,支持:两个int、两个double、两个字符串拼接。

练习4:内联函数练习(难度:★★☆☆☆)

实现内联函数:min、max、clamp(限制范围)。


6. 小结

今日核心要点

[函数重载]
1. 同名函数,参数不同即可重载
2. 参数个数/类型/顺序不同
3. 仅返回值不同不能重载

[默认参数]
4. 语法:void f(int a, int b = 10)
5. 必须从右往左设置默认值
6. 声明和定义只能写一处

[内联函数]
7. inline关键字
8. 适合短小的频繁调用函数
9. 比宏更安全

[constexpr函数]
10. 编译期计算
11. 可用于数组大小等常量表达式

函数特性对照表

特性 C语言 C++
—————————————-
函数重载 ❌ ✅
默认参数 ❌ ✅
内联函数 ❌ ✅ inline
引用参数 ❌ ✅
constexpr ❌ ✅ (C++11)


下一篇预告: Day 4 – 类与对象基础

我们将正式进入面向对象编程,学习类和对象的基本概念。


练习题答案将在 Day 4 开头公布

赞(0)
未经允许不得转载:171主机测评 » 【20天学C++】Day 3: 函数增强
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址