第八章——函数探幽

news2024/9/22 21:34:05

C++内联函数

内联函数是为了提高程序运行速度所做的一项改进。常规函数与内联函数的主要区别不在于编写方式,而在于C++编译器如何将它们组合到程序中。

对于 C++内联函数,编译器将使用相应的函数代码替换函数调用,程序无需跳到另一个位置处执行代码,再跳回来。因此内联函数的运行速度比常规函数稍快,但代价是需要占用更多的内存。所以应该有选择地使用内联函数。

 要使用这项特性,必须采用下述措施之一:

  • 在函数声明前加上关键字inline;
  • 在函数定义前加上关键字inline;

程序员请求将函数作为内联函数,编译器并不一定会满足这种请求,它可能认为该函数过大或函数调用了自己(内联函数不能递归),因此不将其作为内联函数

#include<iostream>
using namespace std;
inline double square(double x) { return x * x; }
int main()
{
	double a, b;
	double c = 13.0;

	a = square(5.0);
	b = square(4.5 + 7.5);
	cout << "a = " << a << " ,b = " << b << endl;
	cout << "c = " <<square(c)<< endl;
	return 0;
}

 

 引用变量

C++新增了一种复合类型——引用变量。引用是已定义的变量的别名(另一个名称)。(例如,如果将twain作为clement变量的引用,则可以交替使用twain和clement来表示该变量)。引用变量的主要用途是用作函数的形参,通过将引用变量用作参数,函数将使用原始数据而不是其副本。 

创建引用变量

 C和C++使用&符号来指示变量的地址。C++给&符号赋予了另一个含义,将其用来声明引用。

例如要将rodents作为rats变量的别名,可以这样做:

int rats;
int & rodents = rats;

 其中&不是地址运算符,而是类型标识符的一部分。就像char*指的是指向char指针,int& 指的是指向int的引用。

上述引用声明允许将rats和rodents互换——它们指向相同的值和内存单元

#include<iostream>
using namespace std;
int main()
{
	int rats = 101;
	int& rodents = rats;
	cout << "rats = " << rats << " at " << &rats<<endl;
	cout << ",rodents = " << rodents <<" at "<<&rodents<< endl;

	rodents++;
	cout << endl;
	cout << "rats = " << rats << " at " << &rats << endl;
	cout << ",rodents = " << rodents << " at " << &rodents << endl;
}

 

注意区分&在下面两个语句中的作用是不一样的

int &rodents = rats;
cout << "at" << &rodents << endl;

第一个语句中&运算符是引用的意思;第二个语句中&运算符是取地址运算符

必须在声明引用时将其初始化,一旦与某个变量关联起来,就一直效忠于它。

 将引用用作函数参数

引用经常被用作函数参数,使得函数中的变量名称为调用程序中的变量别名,这种传递参数的方式称为按引用传递。

 下面用三种方法交换两个变量的值。

#include<iostream>
using namespace std;
void swapr(int& a, int& b);
void swapp(int* p, int* q);
void swapv(int a, int b);
int main()
{
	int wallet1 = 300;
	int wallet2 = 350;
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << endl;

	cout << "Using reference to swap contents:\n";
	swapr(wallet1, wallet2);
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << endl;

	cout << "Using pointers to swap contents again:\n";
	swapp(&wallet1, &wallet2);
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << endl;

	cout << "Trying to use passing by value:\n";
	swapv(wallet1, wallet2);
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << endl;
	return 0;
}

void swapr(int& a, int& b)
{
	int temp;
	temp = a;
	a = b;
	b = temp;
}

void swapp(int* p, int* q)
{
	int temp;
	temp = *p;
	*p = *q;
	*q = temp;
}

void swapv(int a, int b)
{
	int temp;
	temp = a;
	a = b;
	b = temp;
}

 应尽可能使用const

将引用参数声明为常量数据的引用的理由有三个:

  • 使用const可以避免无意中修改数据的编程错误
  • 使用const使函数能够处理const和非const实参,否则将只能接受非const数据
  • 使用const引用使函数能够正确生成并使用临时变量

何时使用引用参数?

 使用引用参数的主要原因有两个:

  • 程序员能够修改调用函数中的数据对象
  • 通过传递引用而不是整个数据对象,可以提高程序的运行速度

当数据对象较大时(如结构和类对象),第二个原因最重要,这些也是使用指针参数的原因。

那么什么时候应使用引用、什么时候应使用指针呢?什么时候应按值传递呢?下面是一些指导原则:

对于使用传递的值而不作修改的函数。

  • 如果数据对象很小,如内置数据类型或小型结构,则按值传递
  • 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针
  • 如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率,这样可以节省复制结构所需的时间和空间
  • 如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用。因此传递类对象参数的标准方式是按引用传递

对于修改调用函数中数据的函数

  • 如果数据对象是内置数据类型,则使用指针
  • 如果数据对象是数组,则只能使用指针
  • 如果数据对象是结构,则使用引用或指针
  • 如果数据对象是类对象,则使用引用

函数重载 

 函数多态是C++在C语言基础上新增的功能。函数多态(重载)让程序员能够使用多个同名的函数。多态和重载这两个术语是同一回事,我们通常使用函数重载。

C++使用上下文来确定要使用的重载函数版本

函数重载的关键是函数的参数列表——也称为函数特征标。如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则它们的特征标相同,而变量名是无关紧要的;如果参数数目或参数类型不同,则特征标也不同,例如,可以定义一组原型如下的print()函数:

void print(const char *str, int width);     #1
void print(double d, int width);            #2
void print(long l, int width);              #3
void print(int i, int width);               #4
void print(const char *str);                #5

使用print()函数时,编译器将根据所采取的用法使用有相应特征标的原型:

print("Pank",15);        // use #1
print("Syrup");          // use #5
print(1999.0,10);        // use #2
print(1999,12);          // use #4
print(1999L,15);         // use #3

 虽然函数重载很诱人,但是不要滥用。仅当函数基本上执行相同的任务,但使用不同形式的数据时,才应采用函数重载。

函数模板

 现在的C++编译器实现了C++新增的一项特性——函数模板。函数模板是通用的函数描述,也就是说它们使用泛型来定义函数,其中的泛型可用具体的类型(如 int 或 double)替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。

假如已经定义了一个交换两个int值的函数,但是现在需要交换两个double值,则一种方法是复制原来的代码,并用double替换所有的int。如果需要交换两个char,可以再一次使用同样的技术。

C++的函数模板功能能自动完成这一过程

函数模板允许以任意类型的方式来定义函数,例如可以这样建立一个交换模板

Template<typename AnyType>
void Swap(AnyType &a,AnyType &b)
{
    AnyType temp;
    temp=a;
    a=b;
    b=temp;
}

 第一行指出要建立一个模板,并将其类型命名为AnyType。关键字template和typename是必需的,除非可以使用关键字class代替typename。另外必须使用尖括号。模板并不创建任何函数,而只是告诉编译器如何定义函数。

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

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

相关文章

LEADTOOLS V22 支持.NET 5-7.0 Crack

使用 LEADTOOLS 构建更好的应用程序 LEADTOOLS 由专利人工智能和机器学习算法提供支持&#xff0c;是一系列综合工具包&#xff0c;可将识别、文档、医疗、成像和多媒体技术集成到桌面、服务器、平板电脑、网络和移动解决方案中。 光学字符识别/ICR 以无与伦比的速度和准确性提…

Django系列所有漏洞复现vulhubCVE-2018-14574,CVE-2022-34265,CVE-2021-35042

文章目录 Django < 2.0.8 任意URL跳转漏洞&#xff08;CVE-2018-14574&#xff09;漏洞详情&#xff1a;复现&#xff1a; Django Trunc(kind) and Extract(lookup_name) SQL注入漏洞&#xff08;CVE-2022-34265&#xff09;漏洞详情&#xff1a;复现&#xff1a; Django Qu…

十五分钟逐步掌握关键路径问题(时间余量、关键活动以及关键路径的求解)

关键路径问题 名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 本篇笔记整理&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 关键路径问题〇、概念说明1、AOE网2、关键路…

微服务系列文章之 nginx负载均衡

nginx负载均衡 负载均衡建立在现有网络结构之上&#xff0c;提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽&#xff0c;增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。 随着网站的发展&#xff0c;服务器压力越来越大&#xff0c;我们可能首先会将数…

虚拟IP绑定公网IP访问

绑定公网 IP 我们目前的虚拟 IP&#xff0c;还不能通过公网的形式进行访问&#xff0c;我们首先&#xff0c;来使用内部的 IP 进行访问看看效果如下&#xff1a; curl 虚拟IP 如上图我访问了两次&#xff0c;第一次访问返回的是 2222 的 nginx&#xff0c;第二次访问是 1111 的…

【SpringCloud-9】JWT

这一篇主要介绍一下&#xff0c;微服务之间的用户权限问题。 通常呢&#xff0c;对于用户的登录鉴权&#xff0c;有两种方式&#xff1a; 1、基于session的方式&#xff1a; session是要存到服务端的&#xff0c;但是分布式服务太多&#xff0c;不可能每个服务端都存。 那就…

Python:文件选择界面 and 文件夹选择界面

文章目录 &#xff08;1&#xff09;文件选择界面&#xff08;2&#xff09;文件夹选择界面 Python本身没有内置的文件夹选择界面。然而&#xff0c;可以使用第三方库来实现在代码中选择文件或文件夹的功能。一个常用的库是tkinter&#xff0c;它是Python的标准GUI库之一&#…

IDEA中侧边栏没有git commit模块,如何恢复?

一、修改之前 侧边栏没有git commit模块 二、修改之后 侧边栏恢复了git commit模块 三、下面是恢复教程 1.中文版 打开 文件 -> 设置 -> 版本控制 -> 提交 -> 勾选 【使用非模式提交界面】 -> 点击【确定】 2.英文版 打开 file -> Settings -> Version Co…

ABB机器人在RobotStudio中进行数字与字符串相互转换的具体方法

ABB机器人在RobotStudio中进行数字与字符串相互转换的具体方法 如下图所示,打开RobotStudio软件,在RAPID—Module1中编写程序,首先声明几个测试需要用到的变量, 本例中利用 NumToStr 函数将数组变量中的元素依次转换成字符后赋值给tempString变量, 如下图所示,利用 StrTo…

第八章 npm锁定版本

1、历史原因 当我们走 npm install 带 ^ 会升级 为什么要锁版本 稳定大于一切 代码需要可控 风险可控 系统可控 环境需要一致

第四章 React18的重要更新和使用的新特性

1、7个新特性 2、3个新API 3、1个新模式 4、2个新并发API 1、7个新特性 Render API 使用了它才可以进入并发模式的渲染 setState自动批处理 有些情况&#xff0c;不希望合并处理 flsuhSync 关于卸载组件时的更新状态警告&#xff08;直接删除这个报错&#xff09; 关于r…

nacos启动问题整理

一 win下启动 1、nacos1.X启动 2、nacos2.X启动 2.x需要jdk11以上版本 1&#xff09;打开bin目录&#xff0c;修改startup.com脚本 启动模式&#xff0c;点击startup.cmd默认启动的集群模式&#xff0c;需要修改这个启动文件 2&#xff09; 连接mysql&#xff0c;执行sql…

【笔记】数字电路基础2 - 数制编码与逻辑电路

目录 数制、编码与逻辑代数数制编码逻辑代数 组合逻辑电路组合逻辑电路分析与设计编码器译码器加法器数值比较器数据选择器奇偶校验器 数制、编码与逻辑代数 数制 本小节主要陈述十进制、二进制、十六进制及其对应的转换法则&#xff0c;网上对应的文章已经有很多&#xff0c;…

一文搞定SpringBoot中日志框架使用

文章目录 Spring Boot 对日志框架的封装SLF4J Logback快速入门调试模式Logback 扩展SLF4J Log4J2 Spring Boot 对日志框架的封装 我们知道在日志方面&#xff0c;SpringBoot默认是使用的SLF4JLogBack的形式。我们来看看它使用的日志实现框架LogBack&#xff0c;其在 Default…

Tomcat、Maven以及Servlet的基本使用

Tomcat什么是TomcatTomcat的目录结构启动Tomcat MavenMaven依赖管理流程配置镜像源 Servlet主要工作实现Servlet添加依赖实现打包分析 配置插件 Tomcat 什么是Tomcat Tomcat 是一个 HTTP 服务器。前面我们已经学习了 HTTP 协议, 知道了 HTTP 协议就是 HTTP 客户端和 HTTP 服务…

LinearAlgebraMIT_4_矩阵的LU分解

矩阵做逆变换需要要反过来&#xff0c;如下&#xff0c; 转置的逆等于逆的转置。 在知道了上面的基础知识后&#xff0c;我们进行矩阵的分解&#xff0c;常见如LU分解和LDU分解&#xff0c;如下&#xff0c; 在这里&#xff0c;我们首先具有一个矩阵A&#xff0c;我们对矩阵A进…

用html+javascript打造公文一键排版系统3:获取参数设置、公文标题排版

我们用自定义函数setDocFmt()来实现对公文的排版。 一、获取公文参数值 要对公文进行排版&#xff0c;首先要读取公文“参数设置”区中的参数值。比如公文要求对公文标题的一般规定是&#xff1a;一般用2号小标宋体字&#xff0c;居中显示。标题与正文中间空一行。 这些是“参…

Git---企业级开发模型

文章目录 前言拓展 一、系统开发环境二、Git分支设计规范master分支release分支develop分支feature分支hotfix分支 三、企业级项目管理实战准备工作创建项目创建仓库添加成员1. 添加企业成员2.添加项目成员3. 添加仓库开发⼈员 开发场景-基于git flow模型的实践新需求加入修复测…

Python之字典(dict)基础知识点

文章目录 一、创建字典1.1 基于dict函数创建1.2 基于{}创建1.3 基于空字典添加元素创建 二、访问字典三、修改字典四、删除字典五、字典的常用方法5.1 dict.items()方法5.2 dict.get()方法5.3 dict.setdefault()方法 参考资料 字典是python当中的一种数据类型&#xff0c;其结果…

Kafka入门,手动提交offset,同步提交,异步提交,指定 Offset 消费(二十三)

手动提交offset 虽然offset十分遍历&#xff0c;但是由于其是基于时间提交的&#xff0c;开发人员难以把握offset提交的实际。因此Kafka还提供了手动提交offset的API 手动提交offset的方法有两种&#xff1a;分别commitSync(同步提交)和commitAsync(异步提交)。两者的相同点是&…