C++学习笔记之三(函数指针、调用、动态内存、模板)
C++
- 1、函数&指针
- 1.1、指针函数
- 1.2、函数指针
- 1.2.1、函数指针作为函数的传入参数
- 1.2.2、函数指针作为函数的返回值
- 2、传递
- 2.1、值传递
- 2.2、址传递
- 2.3、引用传递
- 3、多态
- 3.1、虚方法和抽象方法
- 4、动态内存
- 5、模板
- 5.1、函数模板
- 5.2、类模板
- 5.3、内联函数
1、函数&指针
1.1、指针函数
指针函数是函数,其中指针是定语,函数是名词。意为该函数的返回值为指针。
int *Function_1(void);int temp = 9;
int *p = &temp;int *Function_1(void) //Function函数返回一个int *的指针
{cout<<"I am a function"<<endl;return p; //注意函数的作用域问题,别返回局部指针
}
1.2、函数指针
函数指针是一个指针,其中函数是定语,指针是名词。意为该指针指向函数,即指针内存放的函数的地址。
int (*point)(float); //int指的是函数的返回值类型,float指的是函数的形参类型
举个例子:
int t_function(float); //define a functonint t_function(float num)
{cout<<"the input parameter is: "<<num<<endl;return int(num); //forcing a floating type to an integer
}int main()
{int (*p)(float); //define a function pointorp = t_function; //函数名经过运算之后以地址的形式出现cout<<(*p)(9.9)<<endl;return 0;
}
1.2.1、函数指针作为函数的传入参数
函数指针的本质就是指针,所以函数指针作为传入参数的用法和指针作为传入参数的用法是相同。和一般的数据类型一样,作为形参时,都需要给出完整的定义。而在调用的时候,传入其地址即可。
int add(int,int);
int sub(int,int);
int calc(int (*p)(int,int),int,int); //function pointor as the input parameterint add(int num1,int num2)
{return num1+num2;
}
int sub(int num1,int num2)
{return num1-num2;
}
int calc(int (*p)(int,int),int num1,int num2)
{return (*p)(num1, num2);
}int main()
{int (*p)(int,int); //define a function pointorcout<<calc(add,5,3)<<endl; //input the function's address and the num1,num2.cout<<calc(sub,5,3)<<endl;return 0;
}
1.2.2、函数指针作为函数的返回值
函数指针的声明可以这样写:
int (*function(float))(int,int);
这里充分利用了C语言的运算优先级来分割语句,即括号的优先级大于其他运算符。所以以上的语句可以分为两个部分看,第一个部分 f u n c t i o n ( f l o a t ) function(float) function(float),第二个部分 i n t ( ∗ p ) ( i n t , i n t ) int (*p)(int,int) int(∗p)(int,int)。其中 p p p就是第一部分的 f u n c t i o n ( f l o a t ) function(float) function(float),相当于数学上的换元。
从第一部 f u n c t i o n ( f l o a t ) function(float) function(float)分可以看出,该语句所声明的是一个函数,且该函数有一个 f l o a t float float的传入参数。
从第二部分 i n t ( ∗ p ) ( i n t , i n t ) int (*p)(int,int) int(∗p)(int,int)可以看出,该函数的返回值是一个函数指针,且该函数指针的形式是 i n t ( ∗ p ) ( i n t , i n t ) int (*p)(int,int) int(∗p)(int,int),即该函数指针指向的是一个返回值为 i n t int int类型且两个传入参数都为 i n t int int类型的函数。
最后,在定义该函数的时候当然得把所以形参都加上:
int (*function(float num1))(int num2, int num3)
{cout<<"hello, i am a function and my return value is a function poineter"<<endl;//返回一个函数指针所指向的函数的地址return "a function's address to which the pointer points";
}
2、传递
2.1、值传递
值传递是最简单的一种形式,但囿于太不灵活了。众所周知,每一个函数都有自己的栈区,而值传递就是栈区相互联系的其中一个桥梁。
void Square(int);void Square(int temp)
{int sum = temp*temp;cout<<"the square of this number is:"<<sum<<endl;
}int main()
{int num;cout<<"please enter the number:";cin>>num;Square(num);return 0;
}
该函数的功能是计算传入参数的平方,但无论在 S q u a r e Square Square里面怎么修改 t e m p temp temp,原来的数值 n u m num num还是没有任何改变。究其原因是传值的时候, S q u a r e Square Square会把 n u m num num的值复制下来,放在自己的栈区。
2.2、址传递
void Modify(int*);void Modify(int *temp)
{*temp = 9;
}int main()
{int num;cout<<"please enter the number:";cin>>num;Modify(&num);cout<<"The revised number is:"<<num<<endl;return 0;
}
该函数的功能是把原来的值修改为9,传地址有两个好处,其中一个就是如上的代码所示,可以通过解引用地址来修改原来的值。另一个好处就是,可以传输数组、结构体、类等等东西,因为归根结底,拿到首地址都是可以访问这些结构的。
但传地址的本质还是 M o d i f y Modify Modify把拿到的地址复制一份到自己的栈区,然后再通过解引用自己栈区中的这个地址,去访问或修改原始数据。
2.3、引用传递
通俗的讲,引用传递是给一个变量取一个别名,且通过该别名索引到的内存空间依旧是原来的内存空间。
但从本质上来看,变量名在计算机底层本身就是不存在的,只是给编译器看的而已,所以何来再取一个别名这样的操作。所以在我个人来看,引用还是和指针一样,传递的是一个地址,只不过形式不一样。且引用传递的时候,所调用函数不不复制它到栈区中。这样既节省了内存,也简化了形式。
void Modify(int&);void Modify(int &temp)
{temp = 9;
}int main()
{int num;cout<<"please enter the number:";cin>>num;Modify(num);cout<<"The revised number is:"<<num<<endl;return 0;
}
3、多态
多态性是指用一个函数名字定义若干个函数实现不同的函数,达到在不同情况调用同一函数名执行不同操作的功能。而为了更好的利用多态性,虚方法和抽象方法应运而生。
3.1、虚方法和抽象方法
虚方法是指父类定义一个虚方法,子类可以决定是否要覆盖。如果子类覆盖了,在“父类的指针,子类的对象”这种情况下,以子类的覆盖为准(如 f u n c t i o n 2 function2 function2),否则以父类的函数为主(如 f u n c t i o n 1 function1 function1)。
抽象方法即在形式上和虚方法很像,在其末端加一个 0 0 0而已。但不同的是,抽象方法在父类中是只定义不声明,等到了子类再定义,那么当函数执行的时候,当然有且只有以子类的函数实现为主。
class Superclass
{
public:void function_1(void){cout<<"the father's function 1"<<endl;}virtual void function_2(void){cout<<"the father's function 2"<<endl;}virtual void function_3(void)=0; };class Subclass:public Superclass
{
public:void function_1(void){cout<<"the son's function 1"<<endl;}void function_2(void){cout<<"the son's function 2"<<endl;}void function_3(void){cout<<"the son's function 3"<<endl;}};int main()
{Superclass *p = new Subclass;p->function_1(); //print "the father's function 1"p->function_2(); //print "the son's function 2" p->function_3(); //print "the son's function 3"return 0;
}
4、动态内存
内存按申请阶段分为静态内存和动态内存两种。静态内存是指程序在编译阶段申请内存空间,一般大小固定且不能再修改。比如 i n t int int t e m p temp temp = = = 3 ; 3; 3;这种基本数据类型,都是在编译阶段就给分配好的内存。
动态内存则指在运行阶段才向堆申请内存空间,一般用 n e w new new和 m a l l o c malloc malloc申请的都属于动态内存。
int main()
{int count;cout<<"please assign a value to count:";cin>>count;int *p = new int[count];for(int i=0;i<count;i++){*(p+i) = i;cout<<*(p+i)<<endl;}delete []p; //用这种方式可以释放掉动态数组return 0;
}
5、模板
5.1、函数模板
一般用 t e m p l a t e < t y p e n a m e template<typename template<typename T > T> T>或者 t e m p l a t e < c l a s s template<class template<class T > T> T>来声明一个函数模板。使用模板的好处在于 T T T可以按照需求变成整型 ( i n t ) (int) (int)、浮点型 ( f l o a t ) (float) (float)、地址 ( a d d r e s s ) (address) (address)等等。这避免了传不同的参数就要写不同的重载函数的麻烦。
template <typename T>
void t_function(T); template <typename T>
void t_function(T temp)
{cout<<"the size of temp is:"<<sizeof(temp)<<endl;
}int main()
{int a = 1;double b = 1.0;t_function(a); //print:"the size of temp is 4"t_function(b); //print:"the size of temp is 8"return 0;
}
但使用模板也有一个比较繁琐的点就是每次使用前,都得声明一次。因为我们需要它来告诉编译器如何定义这个函数。
5.2、类模板
类模板其实和函数模板差不多了,只不过是在类的定义前加一个模板罢了。需要注意的部分我也打在注释上了。
template <typename T>
class Car
{
public:Car(T number){cout<<"the car license number is: "<<number<<endl; }~Car(void){cout<<"over"<<endl;}void run(T);
};template <typename T> //you have to declare the template every times you use it.
void Car<T>::run(T kilometer) //Car后面还要加个<T>,代表这个类方法定义的时候用了函数模板
{cout<<"the car ran "<<kilometer<<"km"<<'\n';
}int main()
{class Car <int>mycar(888); //在实例化的时候必须定义类模板是什么类型mycar.run(39);return 0;
}
当然,我们也可以同时使用多个函数模板,像这样。
template <typename T,typename U>
class Car
{
public:Car(T number){cout<<"the car license number is: "<<number<<endl; }~Car(void){cout<<"over"<<endl;}void run(U);
};template <typename T,typename U> //即便只要到了模板U,还是得吧T,U都带上
void Car<T,U>::run(U kilometer)
{cout<<"the car ran "<<kilometer<<"km"<<'\n';
}int main()
{class Car <int,float>mycar(888); //实例化的时候为定义了两种模板mycar.run(39.5);return 0;
}
5.3、内联函数
内联函数是 C + + C++ C++为了提高程序运行速度所做出的一项改进,在函数声明和定义之前加一个 i n l i n e inline inline关键字即可以使函数变成内联函数。
程序运行过程中调用常规函数,跳到对应的栈区执行该函数,执行之后再跳回来,而这会减缓程序运行的速度。内联函数的出现就是为了解决这一问题,内联函数是程序在编译过程中,将函数代码写入到调用它的函数的栈区。从而避免从栈区跳来跳去。譬如 A f u n c t i o n Afunction Afunction中调用到了 B f u n c t i o n Bfunction Bfunction,如果 B f u n c t i o n Bfunction Bfunction是一个常规函数,那么需要从 A f u n c t i o n Afunction Afunction的栈区跳到 B f u n c t i o n Bfunction Bfunction的栈区去执行 B u n c t i o n Bunction Bunction函数再跳回来。但如果 B f u n c t i o n Bfunction Bfunction是一个内联函数,则可以在编译的时候直接把 B f u n c t i o n Bfunction Bfunction的代码写入 A f u n c t i o n Afunction Afunction的栈区,那么当 A f u n c t i o n Afunction Afunction调用到 B f u n c t i o n Bfunction Bfunction的时候,就不需要在栈区之间跳来跳去了。
但这样做有一个缺点就是,如果在这段代码中有 A f u n c t i o n Afunction Afunction, C f u n c t i o n Cfunction Cfunction, D f u n c t i o n Dfunction Dfunction都调用到了 B f u n c t i o n Bfunction Bfunction,那这就会占用更多的内存。所以是否使用内联函数终究是效率和资源之间的平衡。
#include<iostream>
using namespace std;inline void Run(void);inline void Run(void)
{cout<<"running!"<<endl;
}int main()
{Run();return 0;
}
相关文章:
C++学习笔记之三(函数指针、调用、动态内存、模板)
C 1、函数&指针1.1、指针函数1.2、函数指针1.2.1、函数指针作为函数的传入参数1.2.2、函数指针作为函数的返回值 2、传递2.1、值传递2.2、址传递2.3、引用传递 3、多态3.1、虚方法和抽象方法 4、动态内存5、模板5.1、函数模板5.2、类模板5.3、内联函数 1、函数&指针 1…...
【LeetCode】57. 插入区间
1 问题 给你一个 无重叠的 ,按照区间起始端点排序的区间列表。 在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。 示例 1: 输入:interval…...
实时消息传送:WebSocket实现系统后台消息实时通知
实时消息传送:WebSocket实现系统后台消息实时通知 WebSocket简介基本实现步骤后台服务器后端接口SimpMessagingTemplate MessageDto前端客户端 示例应用 在现代Web应用中,提供实时通知对于改善用户体验至关重要。WebSocket技术允许建立双向通信通道&…...
【MATLAB第79期】基于MATLAB的数据抽样合集(sobol、LHS拉丁超立方抽样、Halton、正交/均匀设计、随机rand函数)
【MATLAB第79期】基于MATLAB的数据抽样合集(sobol、LHS拉丁超立方抽样、Halton、正交/均匀设计、随机rand函数) 一、传统函数 1.指定区间随机生成数据(小数) [a b]区间随机数生成: Aa(b-a)rand(m,n) m:待生成矩阵A…...
matlab bin格式转txt输出
matlab bin格式转txt输出 clc,clear; fid fopen(\text.bin,rb); data fread(fid,Inf,int16); fclose(fid);fidfopen(\text.txt,w); fprintf(fid,%d\n,data); fclose(fid);...
Linux之I2C应用编程
I2C-Tools的交叉编译 tar xvf i2c-tools-4.2.tar.xz 首先解压下压缩包 cd i2c-tools-4.2 进入 i2c-tools-4.2目录 make USE_STATIC_LIB1 执行 make 将i2cset ,i2cget ,i2cdump,i2cdetect,i2ctransfer放到板子上 命令直接操作IIC设备 命令行直接操作iic向AP3216C传感器获取数据…...
java 实现定时任务
1、EnableScheduling spring自带的定时任务功能,使用比较简单方便: 1、需要定时执行的方法上加上Scheduled注解,这个注解中可以指定定时执行的规则,稍后详细介绍。 2、Spring容器中使用EnableScheduling开启定时任务的执行&…...
vue3实现在element Dialog 对话框中预览pdf文件
最近有一个需求就是点击按钮在弹框中去预览pdf文件,于是发现了一个HTML中比较重要的标签:embed,前面说的需求就可以用这个标签来实现,一起来学习一下吧。 embed标签是HTML中的一个非常重要的标签,它可以在你的网页上插…...
JVM第十七讲:调试排错 - Java 问题排查之Linux命令
调试排错 - Java 问题排查之Linux命令 本文是JVM第十七讲, Java 问题调试排错。Java 在线问题排查主要分两篇:本文是第一篇,通过linux常用命令排查。 文章目录 调试排错 - Java 问题排查之Linux命令在项目中,日志操作的常用命令1、…...
米哈游、复旦发布,具备感知、大脑、行动的大语言模型“智能体”
ChatGPT等大语言模型展示了前所未有的创造能力,但距AGI(通用人工智能)还有很大的距离,缺少自主决策、记忆存储、规划等拟人化能力。 为了探索大语言模型向AGI演变,进化成超越人类的超级人工智能,米哈游与复…...
企业知识库管理系统怎么做?
21世纪,一个全新的信息化时代,从最初的传统办公到现在的信息化办公,一个世纪的跨越造就了各种大数据的诞生。 知识库系统 在这个数据横行的时代,文档管理产品市场逐渐兴盛起来,企业知识库管理系统作为企业的智慧信息的…...
嵌入式养成计划-45----QT--事件机制--定时器事件--键盘事件和鼠标事件--绘制事件
一百一十五、事件机制 当这件事情发生时,会自动走对应的函数处理(重写的事件函数) 115.1 事件处理简介 什么是事件? (重点) 件是由窗口系统或者自身产生的,用以响应所发生的各类事情,比如用户按下并释放…...
git远程仓库、开发者使用流程、ssh连接
git远程仓库 https://www.cnblogs.com/liuqingzheng/p/15328319.html 远程仓库有: : github gitlab gitee 在gitee上创建了仓库 (确保仓库是空的)本地:git init本地:git commit -m 提交版本指定远程仓库地址 添加一…...
SpringBoot (3) Profiles,外部化配置,自定义starter
目录 1 Profiles 1.1 "组件"环境隔离 1.1.1 标识环境 1.1.2 激活环境 1.2 "配置"环境隔离 1.2.1 添加"副配置文件" 1.2.2 激活环境 2 外部化配置 2.1 配置优先级 2.2 快速部署 3 自定义starter 3.1 基本抽取 3.1.1 导yaml提示包 3…...
【C++】类型转换(dynamic_cast,const_cast,static_cast,reinterpret_cast)
🌏博客主页: 主页 🔖系列专栏: C ❤️感谢大家点赞👍收藏⭐评论✍️ 😍期待与大家一起进步! 文章目录 C语言中的类型转换一、static_cast二、reinterpret_cast三、 const_cast四、 dynamic…...
冷笑话-1
代码检视时,程序员A看着下面的代码,疑惑地问程序员B:“为什么不用重载?” class MyClass {public MyClass queryById(long id) { //......}public MyClass queryByName(String Name) { //......}public MyClass queryByIdAndNam…...
模拟退火算法(SA)求解旅行商问题(TSP)python
目录 一、模拟退火算法求解TSP(city14)的python代码 二、city14的运行结果 三、 模拟退火算法求解TSP(city30)的python代码 四、city30的运行结果 一、模拟退火算法求解TSP(city14)的python代码 impor…...
Intelijj使用Gitee团队开发
初始化项目到Gitee服务器 成功标识: 添加团队成员 点击管理——仓库成员设置——开发者 2.添加仓库成员 (最多不超过5人) 3.通过链接或者二维码邀请新成员,或者可以自己手动添加新成员并提交 多人项目仓库创建完成 通…...
气象台使用vr模拟仿真实训教学降低成本投入
气候仿真实验室用于模拟高低温、高湿、干燥、阳光光照、降雨、降雪、覆冰、雾天与强风等多种环境适应性试验等气候和环境条件,在环境试验中,温度、湿度、光照、降雨这些常见的仿真环境都很容易实现。而比较少见的雾天、强风、降雪等环境就比较难。因此为…...
智能井盖是什么?万宾科技智能井盖传感器有什么特点
智能井盖是一种基于物联网和人工智能技术的新型城市设施。它不仅具备传统井盖的功能,还能通过数字化、自动化的方式实现远程监控和智能管理,提升城市运行效率和服务水平。 WITBEE万宾智能井盖传感器EN100-C2是一款井盖异动监测的传感终端。对窨井盖状态(…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
【AI News | 20250609】每日AI进展
AI Repos 1、OpenHands-Versa OpenHands-Versa 是一个通用型 AI 智能体,通过结合代码编辑与执行、网络搜索、多模态网络浏览和文件访问等通用工具,在软件工程、网络导航和工作流自动化等多个领域展现出卓越性能。它在 SWE-Bench Multimodal、GAIA 和 Th…...
C#学习12——预处理
一、预处理指令: 解释:是在编译前由预处理器执行的命令,用于控制编译过程。这些命令以 # 开头,每行只能有一个预处理指令,且不能包含在方法或类中。 个人理解:就是游戏里面的备战阶段(不同对局…...
【Redis】Redis 的持久化策略
目录 一、RDB 定期备份 1.2 触发方式 1.2.1 手动触发 1.2.2.1 自动触发 RDB 持久化机制的场景 1.2.2.2 检查是否触发 1.2.2.3 线上运维配置 1.3 检索工具 1.4 RDB 备份实现原理 1.5 禁用 RDB 快照 1.6 RDB 优缺点分析 二、AOF 实时备份 2.1 配置文件解析 2.2 开启…...
