C/C++ - 函数进阶(C++)

news2024/11/19 7:23:08

目录

默认参数

函数重载

内联函数

函数模板

递归函数

回调函数


默认参数

  • 定义

    • 默认参数是在函数声明或定义中指定的具有默认值的函数参数。
    • 默认参数允许在调用函数时可以省略对应的参数,使用默认值进行替代。
  • 使用

    • 默认参数可以用于全局函数和成员函数。
    • 默认参数的定义通常放在函数声明中,但也可以在函数定义中进行。
    • 默认参数只能在参数列表的末尾进行定义,即后续参数必须都有默认值。
  • 解析

    • 当调用带有默认参数的函数时,如果省略了对应的参数,编译器会使用默认值进行替代。
    • 如果调用函数时提供了实际参数,则实际参数将覆盖默认参数的值。
    • 默认参数的值在编译时确定,对于每个函数调用都是固定的。
  • 特性

    • 默认参数的定义只能在函数声明或定义中进行一次。
    • 默认参数通常在函数的原型或头文件中进行定义,以便在多个文件中共享。
    • 默认参数的值可以是常量、全局变量、静态变量或其他常量表达式。
  • 示例

    #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;
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1417432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WebRTC 入门:开启实时通信的新篇章(上)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

使用电脑时突然遇到“mfc140.dll文件丢失”的问题都有什么解决办法

当你在使用电脑时突然遇到“mfc140.dll文件丢失”的问题时&#xff0c;可能会感到困惑和苦恼。一旦出现这样的问题&#xff0c;缺少这个文件可能导致一些应用程序无法正常启动&#xff0c;影响你的工作和娱乐体验。其实这个问题是可以解决的&#xff0c;接下来我们将介绍一些可…

部署个人知识库管理软件 MrDoc详细教程

效果 一、拉取 MrDoc 代码 进入目录&#xff1a; cd /opt开源版&#xff1a; git clone https://gitee.com/zmister/MrDoc.git专业版&#xff1a; git clone https://{用户名}:{密码}git.mrdoc.pro/MrDoc/MrDocPro.git二、拉取 Docker 镜像 docker pull zmister/mrdoc:v7三…

yarn安装第三方插件包,提示报错,yarn的镜像源已经过期了,因为yarn和npm用的是淘宝的镜像源,淘宝的镜像源已经过期了,要设置最新的淘宝镜像源。

淘宝最新镜像源切换_淘宝镜像-CSDN博客 查看yarn用的什么镜像源 yarn config get registry 查看具体的信息 yarn config list 设置淘宝的最新镜像源&#xff0c;yarn和npm都要设置最新的淘宝镜像源&#xff0c;不然还是报错 npm config set registry https://registry.npmm…

211毕业38岁产品经理被裁瞒着妻子送外卖

估计很多人都看到这个新闻了&#xff0c;微博和知乎也都上了热搜榜。 有人说&#xff0c;这一看就是摆拍的&#xff0c;谁没事在家里装个摄像头啊&#xff0c;这两人演技也还差点意思。 也有人说&#xff0c;大丈夫能屈能伸。虽然211毕业在互联网大厂工作&#xff0c;但是被裁了…

代码随想录算法训练营Day42|0-1背包理论基础、416. 分割等和子集

目录 0-1背包理论基础 0-1背包问题 二维dp数组01背包 算法实现 一维dp数组01背包 ​编辑算法实现 416. 分割等和子集 前言 思路 算法实现 总结 0-1背包理论基础 0-1背包问题 题目链接https://kamacoder.com/problempage.php?pid1046 有n件物品…

一、Kotlin 开发环境搭建

1. Kotlin 官网 https://kotlinlang.org/ 2. Kotlin 命令行工具下载 下载网址&#xff1a; https://github.com/JetBrains/kotlin/releases/tag/v1.3.50 切换其他版本&#xff0c;改下版本号即可 下载 kotlin-compiler-1.3.50.zip 文件即可 解压 kotlin-compiler-1.3.50.zip…

【智能家居入门之环境信息监测】(STM32、ONENET云平台、微信小程序、HTTP协议)

作为入门本篇只实现微信小程序接收下位机上传的数据&#xff0c;之后会持续发布如下项目&#xff1a;①可以实现微信小程序控制下位机动作&#xff0c;真正意义上的智能家居&#xff1b;②将网络通讯协议换成MQTT协议再实现上述功能&#xff0c;此时的服务器也不再是ONENET&…

回归预测 | MATLAB实现PSO-GRNN粒子群优化广义回归神经网络多输入单输出预测(含优化前后预测可视化)

回归预测 | MATLAB实现PSO-GRNN粒子群优化广义回归神经网络多输入单输出预测 目录 回归预测 | MATLAB实现PSO-GRNN粒子群优化广义回归神经网络多输入单输出预测预测效果基本介绍程序设计参考资料预测效果 <

Cesium.js实现显示点位对应的自定义信息弹窗(数据面板)

零、相关技术选型&#xff1a; Vue2 Vuecli5 Cesium.js 天地图 一、需求说明 在使用2D地图&#xff08;天地图、高德地图等&#xff09;基于官方文档可以实现下面需求&#xff1a; 实现添加点位&#xff0c;并在点位附近显示对应的信息弹窗。 一般信息弹窗的显示方式有两种&am…

Qt线程高级应用

一般我们在用Qt开发时&#xff0c;把耗时操作放在线程中执行&#xff0c;避免卡界面&#xff0c;Qt的线程使用有两种方式&#xff0c;一种是继承QThread&#xff0c;一种是moveToThread的方式&#xff0c;以及QtConcurrent方式 首先我们来看第一种&#xff1a; #ifndef WORKER…

matlab appdesigner系列-仪器仪表3-旋钮

旋钮&#xff0c;同过旋转显示特定的值 示例&#xff1a;模拟收音机调频 操作步骤&#xff1a; 1&#xff09;将旋钮、标签按钮拖拽到画布上&#xff0c;将标签文字修改为&#xff1a;欢迎收听&#xff0c;并将旋钮其数值范围改为90-107 2&#xff09;设置旋钮的回调函数 代…

实现屏蔽 Ctrl + Alt + Del 、Ctrl + Shift + Esc 等热键(一)

前面几篇我们都讲解了很多有关 winlogon 挂钩的事情。拦截系统热键的非驱动方式是比较复杂的。本节就复现《禁止CtrlAltDel、WinL等任意系统热键》一文中的方法四&#xff0c;实现拦截 Ctrl Alt Del 等热键。其实通过 heiheiabcd 给出的方法从 WMsgKMessageHandler 入手并不是…

数字图像处理(实践篇)三十二 OpenCV-Python比较两张图片的差异

目录 一 方案 二 实践 ​通过计算两张图像像素值的均方误差(MSE)来比较两张图像。差异大的两张图片具有较大的均方差值,相反,相似的图片间则具有较小的均方差值。需要注意的是。待比较的两张图像要具有相同的高度、宽度和通道数。 一 方案 ①导入依赖库 import cv2 import…

【项目管理】CMMI-管理性能与度量

管理性能与度量 (Managing Performance and Measurement, MPM)的目的在于开发和维持度量能力来管理开发过程性能&#xff0c;以实现公司业务目标&#xff0c;更直接来说&#xff0c;将管理和改进工作集中在成本、进度表和质量性能上&#xff0c;最大限度地提高业务投资回报。 1…

vscode copilot怎么去掉提示代码(ghost text or incline completion)

原因&#xff1a;最近在刷题&#xff0c;被这个提示烦死了&#xff0c;记录一下怎么关掉&#xff0c;防止将来需要开启找不到了XD. 1.直接ctrlshiftp召唤设置 2.输入preferences: open usr settings找到如图第一个 3.去掉这个方框的勾选 ps直接在extension里disable不行呢 不…

OpenHarmony—仅允许在表达式中使用typeof运算符

规则&#xff1a;arkts-no-type-query 级别&#xff1a;错误 ArkTS仅支持在表达式中使用typeof运算符&#xff0c;不允许使用typeof作为类型。 TypeScript let n1 42; let s1 foo; console.log(typeof n1); // number console.log(typeof s1); // string let n2: typeof …

Arduino Uno R3通过ESP-01S连接网络

一、材料准备 Arduino Uno R3开发板 1 USB串口通信数据线&#xff08;Uno开发板使用&#xff09; 1 ESP8266-01S Wi-Fi模块 1 ESP8266固件烧录下载器&#xff08;烧录固件使用&#xff09; 1 WiFi无线收发转接板&#xff08;适用于ESP-01S、ESP-01&#xff09; 杜邦线…

iOS 面试 Swift基础题

一、Swift 存储属性和计算属性比较&#xff1a; 存储型属性:用于存储一个常量或者变量 计算型属性: 计算性属性不直接存储值,而是用 get / set 来取值 和 赋值,可以操作其他属性的变化. 计算属性可以用于类、结构体和枚举&#xff0c;存储属性只能用于类和结构体。存储属性可…

跟着cherno手搓游戏引擎【13】着色器(shader)

创建着色器类&#xff1a; shader.h:初始化、绑定和解绑方法&#xff1a; #pragma once #include <string> namespace YOTO {class Shader {public:Shader(const std::string& vertexSrc, const std::string& fragmentSrc);~Shader();void Bind()const;void Un…