C++基础——对于C语言缺点的补充(2)

       上篇文章中说到,为了解决C语言会出现人为定义的函数和库函数出现重定义的错误,C++引入了一个新的概念,即命名空间,通过认为定义命名空间,来解决上述问题。

       在本篇文章中,将继续介绍C++相对于C语言不足来进行的补充,例如:缺省参数,重载函数等等。

1. 缺省参数:

1.1 缺省参数的定义以及单个缺省参数简单应用:

       缺省参数的定义大致如下:缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。例如下面的函数:

void PRINT(int a = 0)
{cout << a << endl;
}int main()
{PRINT(0);PRINT(10);return 0;
}

       不难发现,相比C语言中的函数书写方法,C++中,对于函数的形式参数给定了一个初始值0,该值就是上面定义中所说的缺省值。对于这种带有缺省值的函数,其调用结果如下:

       这也证实了定义中的一句话,如果没有对函数的实参进行指定赋值,则在函数执行时默认采用形参,反之采用实参。

1.2 多个缺省参数的应用:

       在上面的情况中,函数只有单一的缺省值。当函数的缺省值数量大于1时,函数的调用方式会更加多样,例如:

void PRINT(int a = 10, int b = 20, int c = 30)
{cout << a << endl;cout << b << endl;cout << c << endl;
}int main()
{PRINT();PRINT(1);PRINT(1, 2);PRINT(1, 2, 3);return 0;
}

 运行结果为:

       通过上面的例子可以看到,针对这种缺省值数量大于1的情况下,函数的调用会因为实参的给定而给出不用的效果。

       但是对于实参数值的给定,需要注意,实参的给定必须是连续的,中间不能有跳跃的情况,例如:

PRINT(, 2, );

1.3 全缺省与半缺省:

      全缺省参数就是上一部分的代码所展示,即所有的形参都给定了缺省值。对于半缺省,则是对于形式参数,不全部给定缺省值,例如:

void PRINT(int a, int b = 20, int c = 30)

但是对于半缺省参数的给定需要注意以下两点:

1. 缺省值必须从右向左给定,且必须是连续的。

2. 当函数的定义和声明分离时,缺省参数不能同时在声明和定义中出现。一般是将缺省参数给定到函数声明中

2. 函数重载:

2.1 函数重载的定义及类型:

       函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。例如下面给出的例子:

int ADD(int num1, int num2)
{cout << "int ADD(int num1, int num2) = ";return num1 + num2;
}double ADD(double num1, double num2)
{cout << " double ADD(double num1, double num2) = ";return num1 + num2;
}
int main()
{cout << ADD(1, 2) << endl;cout << ADD(1.1, 2.2) << endl;
}

       在上述代码中,建立两个函数,且这两个函数函数名相同,都是ADD,但是这两个函数的返回值类型,以及参数类型都不同,此时符合上方函数重载的定义,构成了函数重载。

      对于上述代码,运行结果如下:

         

       上面的例子展示了函数的类型不同,以及其参数类型不同的情况下可以构成重载。当函数的参数数量不同时,即:

void fun()
{cout << "fun()" << endl;
}void fun(int a)
{cout << "fun(a)" << endl;
}
int main()
{fun();fun(1);
}

      此时符合重载定义中参数数量不同这一特性,程序依旧可以正常运行,运行结果如下:

    但是上述函数有一种特殊情况需要注意,即:将函数的参数给定一个缺省值,例如:

void fun()
{cout << "fun()" << endl;
}void fun(int a = 0)
{cout << "fun(a)" << endl;
}
int main()
{fun();fun(1);
}

      运行程序,编译器会报错。这是因为在存在一个不含参数的函数与另一个有参数,且参数有缺省值的情况下,同时运行两个函数会造成二义性,即:编译器不能判断在main函数中,调用函数时,调用的函数是上面两个函数哪一个函数。

    对于函数重载,还有一种方式,即类型的顺序不同,具体情况如下方代码所示:

void fun(int a, char b)
{cout << "void fun(int a, char b)" << endl;
}void fun(char a, int b)
{cout << "void fun(char a, int b)" << endl;
}
int main()
{fun(2, 1.1);fun(2.2, 1);return 0;
}

3. 引用:

3.1 引用的概念以及基本使用:

       在C++中,引用是基于C语言中指针的不足,为解决这些不足创建的。引用的概念如下:引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

      对应代码如下:

int main()
{int a = 1;int& c = a;
}

     main函数中,第一行代码创建了一个名为a的整型变量,第二行则是引用,即给已有的整型变量a取了一个别名叫做c

     在上面的概念中提到,编译器不会为引用变量开辟内存空间,引用与其引用的变量共用一块内存空间。因此,加入对引用进行更改,相应的变量也会更改,例如对于下面代码:

int main()
{int a = 1;int& c = a;cout << "更改前 a=" << a << endl;cout << "更改前 c=" << c << endl;c++;cout << "更改后 a=" << a << endl;cout << "更改后 c=" << c << endl;return 0;
}

运行结果为:

引用不光可以用在已有的变量上,也可以对引用进行引用,即:

int main()
{int a = 1;int& c = a;int& e = c;cout << "a = " << a << endl;cout << "c=" << c << endl;cout << "e=" << e << endl;return 0;
}

 运行结果为:

        对于引用而言,其最大的价值适用于做参数,例如在之前文章中提到到交换函数:

void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}
int main()
{int x = 5;int y = 1;Swap(&x, &y);printf("%d %d", x, y);return 0;
}

        由于函数形参只是实参的一份临时拷贝,形参的改变并不会影响实参,所以在传递参数时,需要传递变量的地址。

        如果利用引用的特性,即:引用的改变会引起变量的改变,来实现交换函数,则可以一定程度上化简上述函数,即:
 

void Swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}
int main()
{int x = 5;int y = 1;Swap(x, y);printf("%d %d", x, y);return 0;
}

      运行结果如下:

3.1 使用引用的注意事项: 

3.1.1 引用与初始化:

       在指针这部分中,如果一个指针只是被创建但是不被初始化,则这个指针称为野指针。不过指针的初始化并不是必然的,但是对于引用来说,必须被初始化,例如:

int main()
{int a = 0;int& b;return 0;
}

由于引用没有被初始化,因此程序错误。

3.1.2 引用能不能被改变指向:

        在数据结构关于的链表的文章中,如果需要在链表中插入一个新的结点,需要改变链表中指针的指向,但是对于引用而言,不能被改变指向,例如:

int main()
{int a = 0;int& b = a;int c = 1;printf("%p %p %p", &a, &b, &c);printf("\n");b = c;cout << "a = " << a << "b = " << b << "c = " << c << endl;printf("%p %p %p", &a, &b, &c);return 0;
}

运行结果如下:


       通过结果不难发现,在执行了b=c这一条代码后,b的地址依旧与a的地址相同,说明没有改变其指向。只是改变了a,b的值。

      因此,引用虽然在一定程度上弥补了指针的不足,但是由于引用并不能改变指向,因此引用并不能完全替代指针。

3.2 引用返回:

3.2.1 引用返回的概念:

在解释本节标题的内容之前,首先需要了解一个概念:

int fun()
{int n = 0;n++;return n;
}
int main()
{int ret = fun();return 0;
}

       图中给定的程序的函数的返回值返回n,在函数外部创建了一个名为ret的变量来接收函数返回值,但是,由于在函数fun运行结束后,该函数对应的栈帧全部销毁,因此,ret并不是直接接收函数的返回值,而是返回值先被存到寄存器中,ret通过寄存器来间接接收这个值。

      此时,如果将函数返回的返回值改为下方代码所示,即:

int& fun()
{int n = 0;n++;return n;
}
int main()
{int ret = fun();return 0;
}

此时再去运行程序,编译器会给出警告。这是因为在这种返回类型下,返回值并不能确定,如果编译器在函数结束后直接清理掉栈帧,则返回空,如果编译器在函数结束后,并不会立即清理掉栈帧,则返回还能有返回值。

(注:由于VS并不会立刻清理掉栈帧,因此运行该程序,返回值会返回1

       通过上面的例子,可以得出一个结论,即:在函数运行结束后,即离开函数的作用域后,此时的返回对象被销毁,因此不能采用引用返回。

但是,对于静态变量和利用malloc类似方式创建的变量,在函数结束后不会销毁,可以采用引用返回。

3.2.2 引用返回的价值:

       由于用返回的价值主要体现在C++的后续内容,因此,本文在此部分指给出结论,原理会在后续的文章中进行阐述。

1. 提高返回速度  

2. 可以修改返回对象

3.3 常引用:

对于常引用,具体可以有下面代码反应:

int main()
{const int a = 1;int& b = a;return 0;
}

        从上面代码可以看到,变量a是一个被const修饰的常变量,下面对变量a进行了一次引用。当去运行上述代码时,编译器会显示错误。

      但是如果将上述代码进行修改,即:

int main()
{const int a = 1;const int& b = a;return 0;
}

       运行此代码时,并没有错误,不难观察到,上下的给的代码唯一的差距就是第二次给出的代码的引用前加了const。因此,在进行常引用的过程中,一定不能涉及变量权限的放大。例如上面运行失败的代码中,原本变量a的权限是不能修改,但是在引用后,由于引用的修改会引起原变量的修改,因此,引用的权限超过了原变量的权限,造成了权限放大。所以导致运行错误。这里需要注意的时,只是不能放大变量的权限,对于变量权限的平移的缩小均无影响,例如:
 

int main()
{int c = 2;const int& d = c;return 0;
}

      上述代码在引用后,缩小了变量的权限,可以正常运行。

      另外,对于一个常量进行常饮用也是允许的,即:

const int& e = 10;

令外,当引用与被引用的对象存在类型转换的情况时,即:

int j = 10;double h = 15;const double& k = j;

由于类型转化的过程中,会额外生成一个常量作用于该过程,引用时k接收的值并不是i,而是i通过一个常量完成类型转换间接传给k,由于常量的常性,因此需要加上const

4. 指针与引用的练习与区别:

     1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
     2. 引用在定义时必须初始化,指针没有要求
     3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体
    4. 没有NULL引用,但有NULL指针
    5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)
   6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
   7. 有多级指针,但是没有多级引用
   8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
   9. 引用比指针使用起来相对更安全

  10.在引用这一小节开头的时候说到,引用是针对一个对象起的别名,与被引用对象共用一块空间。在汇编层上,引用是利用指针来实现的,因此也需要开辟空间。不过,在日常运用时,一般认为引用是不会开辟新空间的。

5. 内联函数:

       对于一般的函数,在函数作用时需要开辟栈帧,而内联函数不需要开辟栈帧,而是在运行中原地展开。由于内联函数不需要开辟栈帧,因此提高了程序的运行效率。

      内敛函数的书写,只需要在函数声明的开头加上inline即可,例如:

inline int Add(int x, int y)
{int z = x + y;return x + y;
}
int main()
{int x = 5;int y = 1;int ret = Add(x, y);return 0;
}

            但是需要注意,内联函数并不能完全替代普通函数,并且,当一个函数的代码函数>10行时,不建议采用内联函数。这是因为,内联函数每次调用时都会原地展开,当调用的次数较大时,例如调用10000次,则一个代码行数为50行的内联函数完全展开后为500000行,延缓程序的运行速度。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Fourier分析导论——第4章——Fourier级数的一些应用(E.M. Stein R. Shakarchi)

第 4 章 傅里叶级数的一些应用 Fourier series and analogous expansions intervene very naturally in the general theory of curves and surfaces. In effect, this theory, conceived from the point of view of analysis, deals obviously with the study of arbitra…

基于MSF控制同一热点(局域网)下的其他设备

主要是基于Metasploit&#xff0c;利于msfvenom生成的恶意软件获取目标shell。 我想各位都很熟悉的一个操作&#xff0c;那就是使用虚拟机当攻击机&#xff0c;本地物理机作为靶机&#xff0c;但这样其实并不能很好的反应出现实情况&#xff0c;有点自己攻击自己的感觉。 因此…

pytorch安装1

用豆瓣源安装pytorch1.5.1&#xff08;速度很快&#xff09;-CSDN博客 详情请参考这位神仙的博客 我真的哭死&#xff0c;原来torch都安装好了&#xff0c;好不容易全部加载好了&#xff0c;但是&#xff0c;gpu配不上去&#xff0c;后来发现还是版本的问题版本不匹配具体版本…

JTS: 16 Orientation 方向

这里写目录标题 版本代码 版本 org.locationtech.jts:jts-core:1.19.0 链接: github 代码 public static void main(String[] args) {OrientationUse orientationUse new OrientationUse();orientationUse.test02();}public void test02() {A new Coordinate(2, 1);B new …

数据结构初阶---复杂度的OJ例题

复杂度的OJ例题 一、消失的数字1.思路一2.思路二3.思路三 二、旋转数组1.思路一2.思路二3.思路三 一、消失的数字 数组nums包含从0到n的所有整数&#xff0c;但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(N)时间内完成吗&#xff1f; 链接&#xff1a;力扣&…

远程管理SSH服务

一、搭建SSH服务 1、关闭防火墙与SELinux # 关闭firewalld防火墙 # 临时关闭 systemctl stop firewalld # 关闭开机自启动 systemctl disable firewalld ​ # 关闭selinux # 临时关闭 setenforce 0 # 修改配置文件 永久关闭 vim /etc/selinux/config SELINUXdisabled 2、配置…

【深度学习】pytorch——Autograd

笔记为自我总结整理的学习笔记&#xff0c;若有错误欢迎指出哟~ 深度学习专栏链接&#xff1a; http://t.csdnimg.cn/dscW7 pytorch——Autograd Autograd简介requires_grad计算图没有梯度追踪的张量ensor.data 、tensor.detach()非叶子节点的梯度计算图特点总结 利用Autograd实…

Transformer:开源机器学习项目,上千种预训练模型 | 开源日报 No.66

huggingface/transformers Stars: 113.5k License: Apache-2.0 这个项目是一个名为 Transformers 的开源机器学习项目&#xff0c;它提供了数千种预训练模型&#xff0c;用于在文本、视觉和音频等不同领域执行任务。该项目主要功能包括&#xff1a; 文本处理&#xff1a;支持…

【Redis】hash数据类型-常用命令

文章目录 前置知识常用命令HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGET关于HMSETHLENHSETNXHINCRBYHINCRBYFLOAT 命令小结 前置知识 redis自身就是键值对结构了&#xff0c;哈希类型是指值本⾝⼜是⼀个键值对结构&#xff0c;形如key"key"&#xff0c;value{{field1…

面向萌新的数学建模入门指南

时间飞逝&#xff0c;我的大一建模生涯也告一段落。感谢建模路上帮助过我的学长和学姐们&#xff0c;滴水之恩当涌泉相报&#xff0c;写下这篇感想&#xff0c;希望可以给学弟学妹们一丝启发&#xff0c;也就完成我的想法了。拙劣的文笔&#xff0c;也不知道写些啥&#xff0c;…

idea必装插件EditStarters(快速引入依赖)

前言 一般来说我们要向一个 servlet 或者 Spring 项目中引入依赖都需要先到中心仓库找到对应的依赖&#xff0c;选择依赖的版本&#xff0c;把依赖添加到配置文件 pom.xml 中&#xff0c;这其实还是有点麻烦的&#xff0c;而通过 EditStarters 插件我们可以迅速的添加依赖到项目…

ElasticSearch高级功能详解与原理剖析

ES数据预处理 Ingest Node Elasticsearch 5.0后&#xff0c;引入的一种新的节点类型。默认配置下&#xff0c;每个节点都是Ingest Node&#xff1a; 具有预处理数据的能力&#xff0c;可拦截lndex或Bulk API的请求对数据进行转换&#xff0c;并重新返回给Index或Bulk APl 无…

万宾科技管网水位监测助力智慧城市的排水系统

以往如果要了解城市地下排水管网的水位变化&#xff0c;需要依靠人工巡检或者排查的方式&#xff0c;这不仅加大了人员的工作量&#xff0c;而且也为市政府带来了更多的工作难题。比如人员监管监测不到位或无法远程监控等情况&#xff0c;都会降低市政府对排水管网的管理能力&a…

自动控制原理答案

题目 现有一个单位反馈系统的开环传递函数为 试对该系统进行以下分析。 1.基础分析 计算该系统的闭环传递函数。 2.稳定性分析 2.1 使用劳斯判据分析该系统的稳定性 2.2 使用MATLAB编程&#xff0c;计算该系统有关于稳定性分析的零、极点&#xff0c;分析其稳定性。 3.暂态性…

京东数据平台:2023年Q3季度黄金市场数据分析

继9月国内黄金市场持续上涨后&#xff0c;进入10月中下旬后&#xff0c;黄金行情再度反转&#xff0c;多家品牌金饰价格再次突破600元/克&#xff0c;达到611元/克。 今年以来&#xff0c;黄金行情不断走俏&#xff0c;销售市场也有明显增长。根据鲸参谋平台的数据显示&#xf…

最受欢迎的程序员副业排行榜TOP6

程序员接单的情况并不少见&#xff0c;因为程序员职业工种的特殊性&#xff0c;能够比较快的衔接上新项目和新技术&#xff0c;所以接私活做副业成了许多程序员的不二之选。 程序员的副业是指程序员在业余时间里从事与编程相关的兼职工作&#xff0c;或者是与技术相关的创业项…

goquery库编写程序

goquery库的爬虫程序&#xff0c;该程序使用Go来爬取视频。。 package main ​ import ("fmt""net/http""net/http/httputil""io/ioutil""log""strings""golang.org/x/net/proxy""golang.org/x/n…

ACWing.第 128 场周赛 (B、C题解)

B、5286. 翻倍&#xff08;思维推导&#xff09; 一、题目要求 给定两个正整数&#xff0c;初始时两数均为 1。 你可以进行任意次&#xff08;也可以不进行&#xff09;翻倍操作&#xff0c;每次操作任选一个非负整数 k&#xff0c;令两数中的一个数乘以 k&#xff0c;另一个…

响应式项目施工装饰工程企业网站模板源码带后台

模板信息&#xff1a; 模板编号&#xff1a;647 模板编码&#xff1a;UTF8 模板颜色&#xff1a;蓝色 模板分类&#xff1a;基建、施工、地产、物业 适合行业&#xff1a;建筑施工类企业 模板介绍&#xff1a; 本模板自带eyoucms内核&#xff0c;无需再下载eyou系统&#xff…

python opencv 实现对二值化后的某一像素值做修改和mask叠加

实现对二值化后的某一像素值做修改 使用OpenCV的findNonZero函数找到所有非零&#xff08;也就是像素值为255&#xff09;的像素&#xff0c;然后遍历这些像素并修改他们的值。示例代码&#xff1a; import cv2 import numpy as np # 加载并二值化图像 img cv2.imread(…