目录
默认参数
函数重载
内联函数
函数模板
递归函数
回调函数
默认参数
-
定义
- 默认参数是在函数声明或定义中指定的具有默认值的函数参数。
- 默认参数允许在调用函数时可以省略对应的参数,使用默认值进行替代。
-
使用
- 默认参数可以用于全局函数和成员函数。
- 默认参数的定义通常放在函数声明中,但也可以在函数定义中进行。
- 默认参数只能在参数列表的末尾进行定义,即后续参数必须都有默认值。
-
解析
- 当调用带有默认参数的函数时,如果省略了对应的参数,编译器会使用默认值进行替代。
- 如果调用函数时提供了实际参数,则实际参数将覆盖默认参数的值。
- 默认参数的值在编译时确定,对于每个函数调用都是固定的。
-
特性
- 默认参数的定义只能在函数声明或定义中进行一次。
- 默认参数通常在函数的原型或头文件中进行定义,以便在多个文件中共享。
- 默认参数的值可以是常量、全局变量、静态变量或其他常量表达式。
-
示例
#include <iostream> #include <Windows.h> int Fun1(int a, int b = 10/*默认参数*/) { return a + b; } //默认参数只能在参数列表的末尾进行定义 //int Fun2(int a, int b = 1, int c) //{ // return a + b + c; //} int Fun2(int a, int b = 1, int c = 2) { return a + b + c; } bool ExitProcess(int nPid = 0) { //TODO //结束进程 //参数PID == 0 则结束自身 否则结束指定进程 if (nPid == 0) { std::cout << "结束自身进程" << std::endl; return 1; } std::cout << "结束指定进程" << std::endl; } int main() { std::cout << Fun1(1) << std::endl; std::cout << Fun2(1) << std::endl; std::cout << Fun2(1 , 2) << std::endl; std::cout << Fun2(1 , 2 , 3) << std::endl; ExitProcess(); ExitProcess(123); return 0; }
函数重载
-
定义
- 函数重载是指在同一作用域内,根据函数的参数类型、参数个数或参数顺序,定义多个具有相同名称但不同特征的函数。
- 通过函数重载,可以使用相同的函数名来表示具有不同行为和功能的函数。
-
使用
- 函数重载允许使用相同的函数名,但函数特征必须不同,包括参数类型、参数个数或参数顺序。
- 函数重载可以应用于全局函数和成员函数。
-
解析
- 在调用重载函数时,编译器会根据函数调用的参数类型、参数个数或参数顺序,选择最匹配的函数进行调用。
- 编译器会进行函数匹配,优先选择完全匹配的重载函数。如果没有完全匹配的函数,编译器会尝试进行隐式类型转换,选择最匹配的函数。
- 如果有多个重载函数都能匹配调用,编译器会产生二义性错误。
-
特性
- 仅根据函数的返回类型不可以进行函数重载。
- 函数重载不能仅通过函数的 const 修饰符进行区分。
- 函数重载不能仅通过函数的参数名进行区分,参数名对于函数重载没有影响。
- 函数重载中的默认参数可以用于区分不同的函数。
-
示例
#include <iostream> //全局作用域 int Add(int a, int b) //整数类型 { return a + b; } float Add(float f1, float f2) //小数类型 { return f1 + f2; } //无法仅通过返回值类型完成重载 //int Fun() //{ // //} // //float Fun() //{ // //} //函数重载不能仅通过函数的 const 修饰符进行区分 //int Fun(int a) //{ // //} // //int Fun(const int a) //{ // //} //函数重载不能仅通过函数的参数名进行区分,参数名对于函数重载没有影响 //int Fun(int a) //{ // //} // //int Fun(int b) //{ // //} int main() { //函数重载 //个数不同 //类型不同 //数量不同 Add(1.0f, 2.0f); Add(1, 1); return 0; }
内联函数
-
定义
- 内联函数是在函数声明或定义中使用 inline 关键字标记的函数。
- 内联函数的主要目的是减少函数调用的开销,将函数的代码插入到函数调用的地方。
-
使用
- 内联函数适用于较短的函数代码,通常在头文件中定义。
- 内联函数可以用于全局函数和成员函数。
-
解析
- 当调用内联函数时,编译器会将函数的代码直接插入到函数调用的地方,而不是生成函数调用的指令。
- 内联函数的展开是在编译时完成的,而不是在运行时。
- 内联函数的展开可能导致代码膨胀,因此适用于较短的函数代码。
-
特性
- 内联函数的定义通常放在头文件中,以便在多个文件中共享。
- 内联函数只是对编译器的建议,编译器可以选择忽略内联函数的建议,特别是对于较大的函数或复杂的函数。
- 内联函数不能递归调用自身。
- 内联函数不能包含复杂的控制流结构,如循环和递归。
-
示例
#include <iostream> //宏函数 #define ADD(X,Y) ((X) + (Y)) //普通函数 int Add1(int a, int b) { return a + b; } //内联函数 inline int Add2(int a, int b) { return a + b; } int main() { //mov dword ptr [a],3 int a = ADD(1, 2); //push 2 //push 1 //call Add1(0401276h) //add esp, 8 //mov dword ptr[b], eax int b = Add1(1, 2); //mov eax, 1 //add eax, 2 //mov dword ptr[c], eax int c = Add2(1, 2); return 0; }
函数模板
-
定义
- 函数模板是一种通用函数的定义,可以用于处理多种类型的参数。
- 函数模板通过在函数声明或定义中使用占位符类型参数来表示参数类型。
-
使用
- 函数模板可以用于全局函数和成员函数。
- 函数模板的定义通常放在头文件中,以便在多个文件中共享。
-
解析
- 函数模板可以进行特化,以处理特定类型的参数或特定情况。
- 显式特化(Explicit Specialization)是指为特定的类型提供具体的函数实现。
- 隐式特化(Implicit Specialization)是指编译器根据参数类型自动选择最匹配的函数实现。
-
特性
- 当调用函数模板时,编译器根据参数类型推断出函数模板的实际类型,并生成对应的函数实例。
- 函数模板的实例化是在编译时完成的。
- 函数模板可以根据需要进行多次实例化,以适应不同的参数类型。
- 函数模板的定义通常放在头文件中,以便在多个文件中共享。
- 函数模板的定义通常包含在类定义或命名空间中。
- 函数模板可以有多个类型参数,以适应多个参数类型的情况。
-
示例
#include <iostream> template <typename CC> CC Compare(CC a, CC b) { return a > b ? a : b; } template <> const char* Compare<const char*>(const char* str1, const char* str2) { return strlen(str1) > strlen(str2) ? str1 : str2; } int main() { std::cout << Compare(1, 2) << std::endl; std::cout << Compare(3, 2) << std::endl; std::cout << Compare(3.15f, 2.5f) << std::endl; std::cout << Compare("CCCCCCCC", "Heeloooooooo") << std::endl; return 0; }
递归函数
-
定义
- 递归函数是在函数的定义中调用自身的函数。
- 递归函数通常用于解决可以通过将问题分解为更小的子问题来解决的问题。
-
使用
- 递归函数可以用于全局函数和成员函数。
- 递归函数的定义通常放在函数声明的后面。
-
终止
- 递归函数必须具有基本情况,也称为终止条件(Termination Condition)。
- 终止条件定义了递归函数何时结束递归调用。
-
递归
- 递归函数在其定义中调用自身,通常使用不同的参数值。
- 递归调用会将问题分解为更小的子问题,并逐步解决这些子问题。
-
特性
- 递归函数必须具有正确的终止条件,以避免无限递归。
- 递归函数的性能可能较低,因为每次递归调用都需要保存函数的状态。
- 递归函数的栈帧可能会占用大量的内存空间,特别是在递归层数较深时。
-
示例
#include <iostream> int Sum(int n) { if (n == 0)return 0; return n + Sum(n - 1); } int main() { int sum = 0; for (int i = 0; i <= 10; i++) { sum += i; } Sum(10); return 0; }
回调函数
-
函数指针
- 函数指针是指向函数的指针变量。
- 函数指针可以用于回调函数,即在程序执行期间将函数作为参数传递给其他函数,并在需要时调用该函数。
-
函数回调
- 函数回调可以通过将函数指针、函数对象或Lambda表达式作为参数传递给其他函数来实现。
- 回调函数可以在需要时被调用,可以传递参数并返回结果。
-
示例
#include <iostream> // 示例1: 函数指针的函数回调 void PrintMessage(const char* message) { std::cout << "Message: " << message << std::endl; } void PerformCallback(void (*callback)(const char*)) { callback("Hello, world!"); } // 示例2: 函数对象的函数回调 struct Callback { void operator()(const char* message) { std::cout << "Message: " << message << std::endl; } }; void PerformCallback(const Callback& callback) { callback("Hello, world!"); } // 示例3: Lambda表达式的函数回调 void PerformCallback(const std::function<void(const char*)>& callback) { callback("Hello, world!"); } int main() { // 示例1: 函数指针的函数回调 PerformCallback(PrintMessage); // 示例2: 函数对象的函数回调 Callback callbackObj; PerformCallback(callbackObj); // 示例3: Lambda表达式的函数回调 PerformCallback([](const char* message) { std::cout << "Message: " << message << std::endl; }); return 0; }