C++ Primer 第6章:函数
6.1 函数基础
6.1.1 函数的定义
函数定义的组成:
┌─────────────────────────────────────────────┐
│ 返回类型 函数名 (参数列表) │
│ { │
│ 函数体 │
│ return 语句; │
│ } │
└─────────────────────────────────────────────┘
// function_basics.cpp -- 函数基础
#include <iostream>
#include <string>
#include <vector>
// 函数定义
int add(int a, int b)
{
return a + b;
}
// 无返回值函数
void printLine(int n, char ch = '-')
{
for (int i = 0; i < n; i++)
std::cout << ch;
std::cout << std::endl;
}
// 返回 bool 的函数
bool isEven(int n)
{
return n % 2 == 0;
}
// 返回 string 的函数
std::string greet(const std::string& name)
{
return "Hello, " + name + "!";
}
int main()
{
using namespace std;
// 函数调用
int sum = add(3, 4);
cout << "3 + 4 = " << sum << endl;
printLine(20);
printLine(20, '*');
cout << boolalpha;
cout << "4是偶数:" << isEven(4) << endl;
cout << "7是偶数:" << isEven(7) << endl;
cout << greet("Alice") << endl;
return 0;
}
6.1.2 函数的调用过程
// call_process.cpp -- 函数调用过程
#include <iostream>
// 调用函数时发生的事情:
// 1. 用实参初始化形参
// 2. 将控制权转移给被调函数
// 3. 执行函数体
// 4. 执行 return 语句,返回值(可选)
// 5. 控制权返回调用点
int factorial(int n)
{
// 函数体中可以定义局部变量
int result = 1;
for (int i = 2; i <= n; i++)
result *= i;
return result; // 返回值
}
// 函数可以有多个 return 语句
int absVal(int n)
{
if (n >= 0)
return n; // 第一个 return
else
return -n; // 第二个 return
}
// void 函数可以有 return 语句(提前返回)
void printPositive(int n)
{
if (n <= 0)
return; // 提前返回,不执行后续代码
std::cout << n << " 是正数" << std::endl;
}
int main()
{
using namespace std;
cout << "5! = " << factorial(5) << endl; // 120
cout << "|-3| = " << absVal(-3) << endl; // 3
printPositive(5);
printPositive(-3); // 不输出任何内容
return 0;
}
6.1.3 局部对象
// local_objects.cpp -- 局部对象
#include <iostream>
// 局部变量:在函数内部定义,函数结束时销毁
// 局部静态变量:在函数内部定义,程序结束时销毁
int countCalls()
{
static int count = 0; // 局部静态变量:只初始化一次
return ++count;
}
void demoLocal()
{
int x = 10; // 局部变量,每次调用都重新初始化
static int y = 0; // 局部静态变量,保留上次的值
x++;
y++;
std::cout << "x=" << x << " y=" << y << std::endl;
}
int main()
{
using namespace std;
// 局部静态变量
cout << "调用次数:" << countCalls() << endl; // 1
cout << "调用次数:" << countCalls() << endl; // 2
cout << "调用次数:" << countCalls() << endl; // 3
cout << "\n局部变量 vs 静态变量:" << endl;
demoLocal(); // x=11 y=1
demoLocal(); // x=11 y=2(x每次重置,y保留)
demoLocal(); // x=11 y=3
return 0;
}
6.1.4 函数声明(原型)
// function_declaration.cpp -- 函数声明
#include <iostream>
// 函数声明(原型):告诉编译器函数的接口
// 可以在头文件中声明,在源文件中定义
double power(double base, int exp); // 声明
bool isPrime(int n); // 声明
int main()
{
using namespace std;
// 可以在定义之前调用(因为有声明)
cout << "2^10 = " << power(2, 10) << endl;
cout << "17是质数:" << boolalpha << isPrime(17) << endl;
return 0;
}
// 函数定义(可以在 main 之后)
double power(double base, int exp)
{
double result = 1.0;
for (int i = 0; i < exp; i++)
result *= base;
return result;
}
bool isPrime(int n)
{
if (n < 2) return false;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
6.2 参数传递
6.2.1 传值参数
// pass_by_value.cpp -- 传值参数
#include <iostream>
// 传值:函数接收实参的副本,修改不影响原变量
void increment(int n)
{
n++; // 修改的是副本
std::cout << "函数内 n = " << n << std::endl;
}
// 传指针:通过指针可以修改原变量
void incrementPtr(int* p)
{
(*p)++; // 通过指针修改原变量
}
// 传指针:重置指针(只影响局部指针副本)
void resetPtr(int* p)
{
p = nullptr; // 只修改局部指针副本,不影响原指针
}
int main()
{
using namespace std;
int x = 5;
// 传值:x 不变
increment(x);
cout << "调用后 x = " << x << endl; // 5
// 传指针:x 改变
incrementPtr(&x);
cout << "incrementPtr后 x = " << x << endl; // 6
// 传指针:指针本身不变
int* p = &x;
resetPtr(p);
cout << "resetPtr后 p = " << (p ? "非空" : "空") << endl; // 非空
return 0;
}
6.2.2 传引用参数
// pass_by_reference.cpp -- 传引用参数
#include <iostream>
#include <string>
// 引用参数:函数可以修改实参
void swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
// const 引用:只读,避免拷贝大对象
void printString(const std::string& s)
{
std::cout << s << " (长度:" << s.size() << ")" << std::endl;
}
// 通过引用返回多个值
void minMax(const std::vector<int>& v, int& minVal, int& maxVal)
{
minVal = maxVal = v[0];
for (int x : v)
{
if (x < minVal) minVal = x;
if (x > maxVal) maxVal = x;
}
}
// 引用参数 vs 指针参数
void byRef(int& r) { r = 100; }
void byPtr(int* p) { *p = 100; }
int main()
{
using namespace std;
// 引用交换
int a = 5, b = 10;
cout << "交换前:a=" << a << " b=" << b << endl;
swap(a, b);
cout << "交换后:a=" << a << " b=" << b << endl;
// const 引用
string longStr = "这是一个很长的字符串,通过const引用传递避免拷贝";
printString(longStr);
// 通过引用返回多个值
vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6};
int minV, maxV;
minMax(nums, minV, maxV);
cout << "最小值:" << minV << " 最大值:" << maxV << endl;
// 引用 vs 指针
int x = 0;
byRef(x);
cout << "byRef后 x = " << x << endl; // 100
x = 0;
byPtr(&x);
cout << "byPtr后 x = " << x << endl; // 100
return 0;
}
6.2.3 const 形参和实参
// const_params.cpp -- const形参
#include <iostream>
#include <string>
// 顶层 const 形参:调用时可以传 const 或非 const 实参
// 但函数内不能修改形参
void func1(const int i) // 顶层const,调用者无感知
{
// i = 10; // ❌ 不能修改
std::cout << "i = " << i << std::endl;
}
// 底层 const(指向const的指针):不能通过指针修改所指对象
void func2(const int* p)
{
// *p = 10; // ❌ 不能修改
std::cout << "*p = " << *p << std::endl;
}
// const 引用:不能修改引用的对象
void func3(const int& r)
{
// r = 10; // ❌ 不能修改
std::cout << "r = " << r << std::endl;
}
// ⚠️ 顶层const在函数重载中不区分
// void func(int i) {}
// void func(const int i) {} // ❌ 重复定义!
// 但底层const可以重载
void print(int* p) { std::cout << "非const指针" << std::endl; }
void print(const int* p) { std::cout << "const指针" << std::endl; }
int main()
{
using namespace std;
int x = 5;
const int cx = 10;
func1(x); // ✅ 传非const
func1(cx); // ✅ 传const
func2(&x); // ✅ 传非const指针
func2(&cx); // ✅ 传const指针
func3(x); // ✅ 传非const
func3(cx); // ✅ 传const
func3(42); // ✅ 传字面值(const引用可以绑定右值)
print(&x); // 调用非const版本
print(&cx); // 调用const版本
return 0;
}
6.2.4 数组形参
// array_params.cpp -- 数组形参
#include <iostream>
#include <string>
// 数组作为参数时,退化为指针
// 以下三种声明等价:
void print1(const int* arr, int size);
void print2(const int arr[], int size);
void print3(const int arr[10], int size); // 10被忽略
void print1(const int* arr, int size)
{
for (int i = 0; i < size; i++)
std::cout << arr[i] << " ";
std::cout << std::endl;
}
// 使用标准库 begin/end 传递范围
void printRange(const int* beg, const int* end)
{
while (beg != end)
std::cout << *beg++ << " ";
std::cout << std::endl;
}
// 多维数组:必须指定除第一维外的所有维度
void print2D(int (*arr)[4], int rows) // 指向含4个int的数组的指针
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < 4; j++)
std::cout << arr[i][j] << "\t";
std::cout << std::endl;
}
}
// 数组引用形参(保留数组大小信息)
void printRef(const int (&arr)[5]) // 只能接受大小为5的数组
{
for (int x : arr)
std::cout << x << " ";
std::cout << std::endl;
}
int main()
{
using namespace std;
int arr[] = {1, 2, 3, 4, 5};
int size = sizeof(arr) / sizeof(arr[0]);
print1(arr, size);
printRange(begin(arr), end(arr));
printRef(arr); // 只能传大小为5的数组
int matrix[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
print2D(matrix, 3);
return 0;
}
6.2.5 main 函数的参数
// main_params.cpp -- main函数的参数
#include <iostream>
#include <string>
// main 函数可以接受命令行参数
// argc:参数个数(包括程序名)
// argv:参数字符串数组
int main(int argc, char* argv[])
{
using namespace std;
cout << "参数个数:" << argc << endl;
cout << "程序名:" << argv[0] << endl;
for (int i = 1; i < argc; i++)
cout << "参数" << i << ":" << argv[i] << endl;
// 也可以写成:
// int main(int argc, char** argv)
// 实际使用示例
if (argc < 2)
{
cout << "用法:" << argv[0] << " <名字>" << endl;
return 1;
}
string name = argv[1];
cout << "Hello, " << name << "!" << endl;
return 0;
}
6.2.6 可变参数
// variadic_params.cpp -- 可变参数
#include <iostream>
#include <initializer_list>
#include <string>
// 方式1:initializer_list(C++11,推荐,类型相同)
double average(std::initializer_list<double> il)
{
double sum = 0;
for (double val : il)
sum += val;
return il.size() > 0 ? sum / il.size() : 0;
}
void printAll(std::initializer_list<std::string> words)
{
for (const auto& w : words)
std::cout << w << " ";
std::cout << std::endl;
}
// 方式2:变参模板(C++11,类型可不同)
template <typename T>
void print(T t)
{
std::cout << t << std::endl;
}
template <typename T, typename... Args>
void print(T first, Args... rest)
{
std::cout << first << " ";
print(rest...); // 递归调用
}
int main()
{
using namespace std;
// initializer_list
cout << "平均值:" << average({1.0, 2.0, 3.0, 4.0, 5.0}) << endl;
printAll({"Hello", "World", "C++"});
// 变参模板
print(1, 2.5, "Hello", 'A');
return 0;
}
6.3 返回类型和 return 语句
6.3.1 无返回值函数
// void_return.cpp -- void函数的return
#include <iostream>
void swap(int& a, int& b)
{
if (a == b)
return; // 提前返回(不需要交换)
int temp = a;
a = b;
b = temp;
}
void printGrade(int score)
{
if (score < 0 || score > 100)
{
std::cout << "无效成绩" << std::endl;
return; // 提前返回
}
if (score >= 90) std::cout << "A" << std::endl;
else if (score >= 80) std::cout << "B" << std::endl;
else if (score >= 70) std::cout << "C" << std::endl;
else if (score >= 60) std::cout << "D" << std::endl;
else std::cout << "F" << std::endl;
}
int main()
{
int a = 5, b = 10;
swap(a, b);
std::cout << "a=" << a << " b=" << b << std::endl;
printGrade(85);
printGrade(-5);
return 0;
}
6.3.2 有返回值函数
// return_value.cpp -- 有返回值函数
#include <iostream>
#include <string>
#include <vector>
// 返回局部变量的值(拷贝)
std::string makeGreeting(const std::string& name)
{
std::string result = "Hello, " + name + "!";
return result; // 返回局部变量的拷贝(安全)
}
// ❌ 不能返回局部变量的引用!
// const std::string& badReturn()
// {
// std::string local = "Hello";
// return local; // 危险!local在函数结束后销毁
// }
// ✅ 可以返回引用(引用的对象在调用者作用域内)
const std::string& getFirst(const std::vector<std::string>& v)
{
return v[0]; // 安全:v 在调用者作用域内
}
// 返回类型为引用,可以作为左值
int& getElement(std::vector<int>& v, int i)
{
return v[i];
}
// 列表初始化返回值(C++11)
std::vector<std::string> makeList()
{
return {"Hello", "World", "C++"}; // 列表初始化
}
int main()
{
using namespace std;
cout << makeGreeting("Alice") << endl;
vector<string> words = {"first", "second", "third"};
cout << getFirst(words) << endl;
vector<int> nums = {1, 2, 3, 4, 5};
getElement(nums, 2) = 99; // 返回引用,可以作为左值
cout << "nums[2] = " << nums[2] << endl; // 99
auto list = makeList();
for (const auto& s : list)
cout << s << " ";
cout << endl;
return 0;
}
6.3.3 递归函数
// recursion.cpp -- 递归函数
#include <iostream>
#include <string>
// 递归:函数调用自身
// 必须有基准情形(终止条件)
// 阶乘
long long factorial(int n)
{
if (n <= 1) return 1; // 基准情形
return n * factorial(n - 1); // 递归情形
}
// 斐波那契数列
int fibonacci(int n)
{
if (n <= 0) return 0;
if (n == 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 二分查找(递归版本)
int binarySearch(const int arr[], int low, int high, int target)
{
if (low > high) return -1; // 基准情形:未找到
int mid = low + (high - low) / 2;
if (arr[mid] == target) return mid;
if (arr[mid] > target)
return binarySearch(arr, low, mid - 1, target);
else
return binarySearch(arr, mid + 1, high, target);
}
// 打印缩进树形结构
void printTree(const std::string& name, int depth = 0)
{
for (int i = 0; i < depth; i++)
std::cout << " ";
std::cout << name << std::endl;
}
int main()
{
using namespace std;
// 阶乘
for (int i = 0; i <= 10; i++)
cout << i << "! = " << factorial(i) << endl;
// 斐波那契
cout << "\n斐波那契数列:";
for (int i = 1; i <= 10; i++)
cout << fibonacci(i) << " ";
cout << endl;
// 二分查找
int arr[] = {1, 3, 5, 7, 9, 11, 13, 15};
int n = sizeof(arr) / sizeof(arr[0]);
int idx = binarySearch(arr, 0, n - 1, 7);
cout << "\n查找7:位置 " << idx << endl;
return 0;
}
6.4 函数重载
// overloading.cpp -- 函数重载
#include <iostream>
#include <string>
// 重载:同名函数,不同参数列表
// 编译器根据实参类型选择正确的版本
void print(int i)
{
std::cout << "int: " << i << std::endl;
}
void print(double d)
{
std::cout << "double: " << d << std::endl;
}
void print(const std::string& s)
{
std::cout << "string: " << s << std::endl;
}
void print(int i, int j)
{
std::cout << "two ints: " << i << ", " << j << std::endl;
}
// 重载与 const
void process(int& r)
{
std::cout << "非const引用" << std::endl;
}
void process(const int& r)
{
std::cout << "const引用" << std::endl;
}
// ❌ 以下不构成重载(仅返回类型不同)
// int getValue() { return 1; }
// double getValue() { return 1.0; } // 错误!
// ❌ 顶层const不构成重载
// void func(int i) {}
// void func(const int i) {} // 错误!重复定义
int main()
{
using namespace std;
print(42); // 调用 print(int)
print(3.14); // 调用 print(double)
print(string("Hi")); // 调用 print(string)
print(1, 2); // 调用 print(int, int)
int x = 5;
const int cx = 10;
process(x); // 调用非const版本
process(cx); // 调用const版本
process(42); // 调用const版本(字面值绑定const引用)
return 0;
}
6.5 特殊用途语言特性
6.5.1 默认实参
// default_args.cpp -- 默认实参
#include <iostream>
#include <string>
// 默认实参:从右向左设置
void createWindow(int width = 800,
int height = 600,
const std::string& title = "My Window")
{
std::cout << "创建窗口:" << width << "x" << height
<< " 标题:" << title << std::endl;
}
// 默认实参通常在函数声明中指定
std::string format(double val, int precision = 2, char sep = '.');
int main()
{
using namespace std;
createWindow(); // 使用所有默认值
createWindow(1024); // 指定宽度
createWindow(1024, 768); // 指定宽高
createWindow(1920, 1080, "Full HD"); // 全部指定
// ⚠️ 不能跳过中间的参数
// createWindow(, , "Title"); // ❌ 错误!
return 0;
}
std::string format(double val, int precision, char sep)
{
// 简化实现
return std::to_string(val);
}
6.5.2 内联函数
// inline_function.cpp -- 内联函数
#include <iostream>
// inline:建议编译器将函数调用替换为函数体
// 适合短小、频繁调用的函数
inline int max(int a, int b)
{
return (a > b) ? a : b;
}
inline bool isPositive(double x)
{
return x > 0;
}
inline int square(int x)
{
return x * x;
}
// 内联函数通常定义在头文件中
// 因为编译器需要看到函数定义才能内联展开
int main()
{
using namespace std;
// 编译器可能将 max(3, 5) 展开为 (3 > 5) ? 3 : 5
cout << "max(3, 5) = " << max(3, 5) << endl;
cout << "isPositive(-1) = " << boolalpha << isPositive(-1) << endl;
cout << "square(7) = " << square(7) << endl;
// 内联函数 vs 宏
// 宏:#define MAX(a,b) ((a)>(b)?(a):(b))
// 问题:MAX(x++, y++) 会导致 x 或 y 被递增两次!
// 内联函数没有这个问题
int x = 5, y = 3;
cout << "max(x++, y++) = " << max(x++, y++) << endl;
cout << "x=" << x << " y=" << y << endl; // x=6, y=4(各递增一次)
return 0;
}
6.5.3 constexpr 函数
// constexpr_function.cpp -- constexpr函数
#include <iostream>
#include <array>
// constexpr 函数:可以在编译时求值
// 函数体只能包含一条 return 语句(C++11)
// C++14 放宽了限制
constexpr int factorial(int n)
{
return n <= 1 ? 1 : n * factorial(n - 1);
}
constexpr double circleArea(double r)
{
return 3.14159265358979 * r * r;
}
// C++14:constexpr 函数可以有更复杂的函数体
constexpr int fibonacci(int n)
{
if (n <= 0) return 0;
if (n == 1) return 1;
int a = 0, b = 1;
for (int i = 2; i <= n; i++)
{
int c = a + b;
a = b;
b = c;
}
return b;
}
int main()
{
using namespace std;
// 编译时计算
constexpr int f5 = factorial(5); // 编译时:120
constexpr double area = circleArea(5.0);
cout << "5! = " << f5 << endl;
cout << "圆面积(r=5) = " << area << endl;
// 用于数组大小(必须是编译时常量)
constexpr int SIZE = factorial(4); // 24
array<int, SIZE> arr;
cout << "数组大小:" << arr.size() << endl;
// 运行时也可以调用
int n;
cin >> n;
cout << n << "! = " << factorial(n) << endl;
return 0;
}
6.6 函数匹配
// function_matching.cpp -- 函数匹配规则
#include <iostream>
void f(int) { std::cout << "f(int)" << std::endl; }
void f(double) { std::cout << "f(double)" << std::endl; }
void f(int, int) { std::cout << "f(int,int)" << std::endl; }
int main()
{
using namespace std;
f(42); // 精确匹配:f(int)
f(3.14); // 精确匹配:f(double)
f(42, 0); // 精确匹配:f(int,int)
// 类型提升
f(true); // bool → int:f(int)
f('a'); // char → int:f(int)
// 标准转换
// f(42L); // long → int 或 long → double,二义性!
// 函数匹配步骤:
// 1. 确定候选函数(同名函数)
// 2. 确定可行函数(参数数量和类型匹配)
// 3. 寻找最佳匹配(精确匹配 > 提升 > 标准转换)
return 0;
}
6.7 函数指针
// function_pointer.cpp -- 函数指针
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
// 函数指针:指向函数的指针
// 声明:返回类型 (*指针名)(参数类型列表)
bool lengthCompare(const std::string& s1, const std::string& s2)
{
return s1.size() < s2.size();
}
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
// 函数指针作为参数
void applyAndPrint(int a, int b, int (*op)(int, int))
{
std::cout << "结果:" << op(a, b) << std::endl;
}
// 返回函数指针
int (*getOperation(char op))(int, int)
{
switch (op)
{
case '+': return add;
case '-': return sub;
case '*': return mul;
default: return nullptr;
}
}
// 使用 using 简化函数指针类型
using BinaryOp = int(*)(int, int);
using Comparator = bool(*)(const std::string&, const std::string&);
int main()
{
using namespace std;
// 声明函数指针
bool (*pf)(const string&, const string&) = lengthCompare;
// 调用函数指针
cout << boolalpha;
cout << pf("hello", "hi") << endl; // false(hello更长)
// 函数名可以直接赋给函数指针(自动取地址)
pf = &lengthCompare; // 等价于上面
// 用于排序
vector<string> words = {"banana", "apple", "cherry", "fig"};
sort(words.begin(), words.end(), pf); // 按长度排序
for (const auto& w : words) cout << w << " ";
cout << endl;
// 函数指针作为参数
applyAndPrint(10, 3, add);
applyAndPrint(10, 3, sub);
applyAndPrint(10, 3, mul);
// 返回函数指针
BinaryOp op = getOperation('+');
if (op) cout << "10 + 3 = " << op(10, 3) << endl;
// 函数指针数组
BinaryOp ops[] = {add, sub, mul};
string opNames[] = {"add", "sub", "mul"};
for (int i = 0; i < 3; i++)
cout << opNames[i] << "(10, 3) = " << ops[i](10, 3) << endl;
return 0;
}
6.8 综合示例:计算器
// calculator.cpp -- 综合示例:函数式计算器
#include <iostream>
#include <string>
#include <map>
#include <functional>
#include <stdexcept>
#include <cmath>
#include <iomanip>
// 使用 std::function 存储各种可调用对象
using BinaryFunc = std::function<double(double, double)>;
using UnaryFunc = std::function<double(double)>;
// 二元运算
double safeDiv(double a, double b)
{
if (b == 0) throw std::runtime_error("除数不能为零");
return a / b;
}
double safeMod(double a, double b)
{
if (b == 0) throw std::runtime_error("模数不能为零");
return std::fmod(a, b);
}
double power(double base, double exp)
{
return std::pow(base, exp);
}
// 一元运算
double mysqrt(double x)
{
if (x < 0) throw std::domain_error("不能对负数开方");
return std::sqrt(x);
}
// 计算器类
class Calculator
{
private:
std::map<std::string, BinaryFunc> binaryOps;
std::map<std::string, UnaryFunc> unaryOps;
double memory = 0; // 内存存储
public:
Calculator()
{
// 注册二元运算
binaryOps["+"] = [](double a, double b) { return a + b; };
binaryOps["-"] = [](double a, double b) { return a - b; };
binaryOps["*"] = [](double a, double b) { return a * b; };
binaryOps["/"] = safeDiv;
binaryOps["%"] = safeMod;
binaryOps["pow"] = power;
binaryOps["max"] = [](double a, double b) { return std::max(a, b); };
binaryOps["min"] = [](double a, double b) { return std::min(a, b); };
// 注册一元运算
unaryOps["sqrt"] = mysqrt;
unaryOps["abs"] = [](double x) { return std::abs(x); };
unaryOps["sin"] = [](double x) { return std::sin(x); };
unaryOps["cos"] = [](double x) { return std::cos(x); };
unaryOps["log"] = [](double x) {
if (x <= 0) throw std::domain_error("log的参数必须为正");
return std::log(x);
};
}
double calculate(double a, const std::string& op, double b)
{
auto it = binaryOps.find(op);
if (it == binaryOps.end())
throw std::invalid_argument("未知运算符:" + op);
return it->second(a, b);
}
double calculate(const std::string& op, double a)
{
auto it = unaryOps.find(op);
if (it == unaryOps.end())
throw std::invalid_argument("未知函数:" + op);
return it->second(a);
}
void storeMemory(double val) { memory = val; }
double recallMemory() const { return memory; }
};
int main()
{
using namespace std;
Calculator calc;
// 测试二元运算
cout << "===== 二元运算 =====" << endl;
struct TestCase { double a; string op; double b; };
vector<TestCase> tests = {
{10, "+", 3}, {10, "-", 3}, {10, "*", 3},
{10, "/", 3}, {10, "%", 3}, {2, "pow", 10},
{10, "max", 20}, {10, "min", 20}
};
for (const auto& t : tests)
{
try
{
double result = calc.calculate(t.a, t.op, t.b);
cout << fixed << setprecision(4)
<< t.a << " " << t.op << " " << t.b
<< " = " << result << endl;
}
catch (const exception& e)
{
cout << "错误:" << e.what() << endl;
}
}
// 测试一元运算
cout << "\n===== 一元运算 =====" << endl;
struct UnaryTest { string op; double val; };
vector<UnaryTest> utests = {
{"sqrt", 16}, {"abs", -5}, {"sin", 0},
{"cos", 0}, {"log", 2.718}
};
for (const auto& t : utests)
{
try
{
double result = calc.calculate(t.op, t.val);
cout << t.op << "(" << t.val << ") = "
<< fixed << setprecision(4) << result << endl;
}
catch (const exception& e)
{
cout << "错误:" << e.what() << endl;
}
}
// 测试错误处理
cout << "\n===== 错误处理 =====" << endl;
try { calc.calculate(10, "/", 0); }
catch (const exception& e) { cout << "捕获:" << e.what() << endl; }
try { calc.calculate("sqrt", -4); }
catch (const exception& e) { cout << "捕获:" << e.what() << endl; }
return 0;
}
📝 第6章知识点总结
| 知识点 |
核心要点 |
| 函数定义 |
返回类型+函数名+参数列表+函数体,局部变量在函数结束时销毁 |
| 局部静态变量 |
static 修饰,只初始化一次,程序结束时销毁,保留上次的值 |
| 函数声明 |
原型告诉编译器接口,可以在定义前调用,通常放在头文件 |
| 传值参数 |
函数接收副本,修改不影响原变量 |
| 传引用参数 |
函数可以修改原变量,避免大对象拷贝 |
| const引用 |
只读参数,可以接受字面值和右值,推荐用于大对象 |
| 数组参数 |
退化为指针,必须同时传大小;数组引用保留大小信息 |
| 可变参数 |
initializer_list(同类型)或变参模板(不同类型) |
| 返回引用 |
不能返回局部变量的引用,可以返回引用参数或静态变量 |
| 递归 |
必须有基准情形,每次调用向基准靠近 |
| 函数重载 |
同名不同参数,返回类型不同不构成重载,顶层const不区分 |
| 默认实参 |
从右向左设置,调用时可省略右侧参数 |
| 内联函数 |
建议编译器展开,适合短小频繁调用,通常定义在头文件 |
| constexpr函数 |
编译时求值,可用于数组大小等常量表达式场景 |
| 函数指针 |
返回类型(*ptr)(参数类型),可作为参数和返回值 |