C++基础入门(二)(函数重载,引用,内联函数,nullptr)

目录

一. 函数重载

1. 概念

2. 实现

(1). 参数类型不同

(2). 参数个数不同

(3). 参数类型顺序不同

3. 注意事项

(1). 返回值不能作为重载的条件

(2). 不能仅按函数返回类型重载

(3). 与缺省参数的问题

二. 引用

1. 概念和定义

2. 引用的特性

(1). 引用在定义时必须初始化

(2). 一个变量可以有多个引用

(3). 引用一旦引用一个实体,再不能引用别的实体

3. 引用的使用

4. 引用做函数返回值

5. const 引用

 6. 指针和引用的关系

三. 内联函数

概念

 使用

 注意

 四. nullptr


一. 函数重载

1. 概念

C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔不⽀持同⼀作⽤域中出现同名函数的。

2. 实现

有三个使用情景,分别为参数类型不同,参数个数不同和参数类型顺序不同

(1). 参数类型不同
#include<iostream>using namespace std;
int Add(int aaaa, int bbbb)
{cout << "调用的是整数相加的函数" << endl;return aaaa + bbbb;
}double Add(double aaaa, double bbbb)
{cout << "调用的是双精度浮点数相加的函数" << endl;return aaaa + bbbb;
}int main()
{int a = 10, b = 22;double aa = 0.221, bb = 3.025;cout << a << " " << b << endl;cout << aa << " " << bb << endl;return 0;
}
(2). 参数个数不同
#include<iostream>using namespace std;
void n()
{cout << "调用的是无参数的函数" << endl;
}
void n(int a)
{cout << "调用的是有参数a的函数" << endl;
}int main()
{n();n(2);return 0;
}
(3). 参数类型顺序不同

#include<iostream>
using namespace std;
void nn(int a,char b)
{cout << "调用的是先int型数据再char型数据的函数" << endl;
}
void nn(char a,int b)
{cout << "调用的是先char型数据再int型数据的函数" << endl;
}
int main()
{nn(1, 'x');nn('x', 1);return 0;
}
3. 注意事项
(1). 返回值不能作为重载的条件

例如一下两个函数

int nn(int a,char b)
{return 1;
}int nn(int b,char a)
{return 0;
}

进行函数调用时并不能区分两个函数的差别,所以不可以

(2). 不能仅按函数返回类型重载

如下两个函数

void nn(int a,char b)
{printf("1111\n");
}int nn(int b,char a)
{return 0;
}
(3). 与缺省参数的问题
#include<iostream>using namespace std;void ffff()
{cout << "111111111" << endl;
}
void ffff(int a = 10)
{cout << a << endl;
}int main()
{	ffff(110);ffff();return 0;
}

以上两个代码构成重载

我们发现仅调用ffff(110);可以正常进行,但调用f();直接会报错,因为存在歧义,编译器会不知道调用谁

二. 引用

1. 概念和定义

引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间, 它和它引⽤的变量共⽤同⼀块内存空间。就像人会有小名一样,例如张三,他的家人可能平时叫他小三,虽然称呼不同,但都是叫的张三这一个人

定义方法为:

类型& 引用别名 = 引用对象

C++中为了避免引入太多运算符,会复用C语言的一些符号,比如前面的<<和>>,这里引用和取地址使用了同一个符号,注意使用方法区分即可。

#include<iostream>
using namespace std;
int main()
{int aa = 0;//bb和cc是aa的别名int& bb = aa;int& cc = aa;//给别名bb取别名,dd仍然是aa的别名int& dd = bb;++dd;cout << aa << "  " << &aa << endl;cout << bb << "  " << &bb << endl;cout << cc << "  " << &cc << endl;cout << dd << "  " << &dd << endl;return 0;
}

假设a的别名是b,那b就等同于a

别名的别名d依然等同于其本身

2. 引用的特性
(1). 引用在定义时必须初始化

错误代码如下

#include<iostream>
using namespace std;
int main()
{int a = 111;int& aa;return 0;
}

 修改为

#include<iostream>
using namespace std;
int main()
{int a = 111;int& aa=a;return 0;
}
(2). 一个变量可以有多个引用

即一个人可以有多个称呼

#include<iostream>
using namespace std;
int main()
{int a = 111;int& aa=a;int& aaa = a;int& aaaa = a;return 0;
}
(3). 引用一旦引用一个实体,再不能引用别的实体

如下所示

#include<iostream>
using namespace std;
int main()
{int a = 111;int& aa=a;int c = 20;aa = c;cout << a << " " << aa << endl;return 0;
}

其中的 aa = c ; 并非是让aa称为c的别名,因为C++不能改变指向,这里是一个赋值操作

3. 引用的使用

在平时的实践中引用主要是在引用传参和引用做返回值中减少拷贝,提高效率。并且在改变引用对象时同时改变被引用对象

引用传参跟指针传参功能是类似的,引用传参相对更方便一些

代码如下

#include<iostream>
using namespace std;void Swap1(int* a, int* c)
{*a = 20;*c = 111;
}void Swap2(int& a, int& c)
{a = 20;c = 111;
}int main()
{int a1 = 111;int a2 = 111;int c1 = 20;int c2 = 20;Swap1(&a1, &c1);Swap2(a2, c2);cout << a1 << " " << c1 << endl;cout << a2 << " " << c2 << endl;return 0;
}

 我们发现两种方式均完成了改变

在之前数据结构的时间中我们都是传的指针但是也可以通过引用来替代

int StackSize(ST* ps)
{assert(ps);return ps->top;//栈的大小
}int StackSize(ST& ps)
{return ps.top;//栈的大小
}

 上述代码效果相同

指针变量也可以取别名

比如

void Push(pNode** pd,int x)
{//...........
}void Push(pNode*& pd,int x)
{//...........
}

这里的pNode*& pd就是给指针变量取别名,这样就不需要用二级指针了,相对而言简化了程序

4. 引用做函数返回值

不要返回局部变量引用

由于函数执行完毕时,局部变量的内存空间会被系统自动回收。如果此时外部代码试图通过引用访问该局部变量,实际上访问的是已经被回收的内存空间,被称为野引用或空引用,造成严重后果

返回值可以用引用接收

如果函数的返回值是引用那么这个函数调用可以做左值

#include<iostream>
using namespace std;int a = 100;
int& ppp()
{return a;
}
int main()
{int& c = ppp();ppp() = 10;cout << c << endl;return 0;
}

由于返回值是a的别名,所以可以直接通过赋值来改变他

5. const 引用

可以引用一个const对象,但是必须用const引用。const引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大。

#include<iostream>
#include"stack.h"
using namespace std;int main()
{const int aa = 10;//自身不能改变,别名自然也不能改变//int& d = aa;const int& c = aa;int b = 20;//权限可以缩小,不能放大const int& f = b;//int& e = f;//不可以增大权限//int& p = 30;const int& p = 30;return 0;
} 

const引用还可以引用常数

而在下列代码中

#include<iostream>
#include"stack.h"
using namespace std;int main()
{int a = 1;int b = 2;//int& t = (a + b);const int& t = (a + b);//引用的是临时对象,临时对象生命周期就跟着引用走//(临时对象在,两数加减乘除等,函数传值返回,类型转换 产生)double dd = 1.21;int i = dd;//int& pp = dd;const int& pp = dd;return 0;
} 

 上述引用,都是引用的临时对象,(a+b)结果保存在一个临时对象中,类型转换时也会产生临时对象来存储中间值,C++规定临时对象具有常性,所以想要引用就会触发权限放大,必须使用常引用

所谓的临时对象就是编译器需要一个空间暂存表达式的求值结果时创建的一个未命名的对象,C++中把这个未命名对象叫做临时对象。引用后临时对象生命周期就跟着引用走临时对象一般在,两数加减乘除等,函数传值返回,类型转换时产生

 6. 指针和引用的关系

在实践中,功能具有重叠性,但是各有自己的特点,互相不可代替。

在语法概念上,引用是一个变量取别名不额外开辟空间,指针是存储一个变量地址,要开空间。

引用在定义时必须初始化,指针建议初始化,但不是必须的

引用在初始化时引用一个对象后,就不能再引用其他对象;而指针可以再不断改变指向对象。

引用可以直接访问指向对象,指针需要解引用才能访问指向对象

sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下站4个字节,64位下占8字节)

指针经常出现空指针和野指针问题,引用很少出现,使用起来相对安全些

引用的底层实现与指针其实没有什么区别

三. 内联函数

概念

⽤inline修饰的函数叫做内联函数,编译时C++编译器会在调⽤的地⽅展开内联函数,这样调⽤内联函数就不需要建⽴栈帧了,就可以提⾼效率。用来替换C语言中的宏函数,因为宏函数也会在预处理时替换展开,但宏函数的实现很复杂很容易出错,且不方便调试2,C++设计inline的目的就是替代C的宏函数

 使用

 nline对于编译器⽽⾔只是⼀个建议,也就是说,你加了inline编译器也可以选择在调⽤的地⽅不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适⽤于频繁调⽤的短⼩函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略

 因为其本质上就是空间换时间,假设内联函数本身有1000条指令,有100个位置调用他,不展开的话是 1000+100条指令 ,展开的话是1000*100条指令

#include<iostream>
#include"stack.h"
using namespace std;inline int Add(int a, int b)
{int s = a + b;return s;
}int main()
{int s = Add(5, 2);cout << Add(5, 2) * 5 << endl;return 0;
}

 vs编译器debug版本下面默认是不展开inline的,这样方便调试,可以修改,步骤如下

 注意

inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。使用内联函数时声明处不能展开,所以只能找其地址(相当于内联属性没有了),但函数实现那里又认为自己是内联函数所以出现错误

 四. nullptr

NULL实际上是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL    #ifdef __cplusplus#define NULL    0    #else       #define NULL    ((void *)0) #endif
#endif

C++中NULL可能被定义为字⾯常量0,或者C中被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到⼀些麻烦,如下代码

#include<iostream>
#include"stack.h"
using namespace std;void fff(int x)
{cout << "整数" << endl;
}void fff(int* x)
{cout << "指针" << endl;
}int main()
{fff(1);fff(NULL);fff((int*)NULL);//fff((void*)NULL);return 0;
}

上述代码结果为

本想通过fff(NULL);调⽤指针版本的fff(int* x);函数,但是由于NULL被定义成0调⽤了fff(int x);,因此与程序的初衷相悖。fff((void*)NULL);调用则会报错

C++11中引⼊nullptr来代替NULL,nullptr是⼀个特殊的关键字,nullptr是⼀种特殊类型的字⾯量,值是空指针它的类型可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,不会被隐式转换为整数类型


这篇文章就到这里啦,如果帮到你可以点点赞

(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤

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

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

相关文章

【多任务YOLO】 A-YOLOM: You Only Look at Once for Real-Time and Generic Multi-Task

You Only Look at Once for Real-Time and Generic Multi-Task 论文链接&#xff1a;http://arxiv.org/abs/2310.01641 代码链接&#xff1a;https://github.com/JiayuanWang-JW/YOLOv8-multi-task 一、摘要 高精度、轻量级和实时响应性是实现自动驾驶的三个基本要求。本研究…

HTML5实现好看的天气预报网站源码

文章目录 1.设计来源1.1 获取天气接口1.2 PC端页面设计1.3 手机端页面设计 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_4…

深入理解PHP基础【代码审计实战指南】

文章目录 基础语法单双引号的区别前后端分离数据类型PHP常量函数var_dump函数count函数print_r函数**readfile&#xff08;&#xff09;函数****file_get_contents()函数****file_put_contents()函数**header函数fopen函数fread 函数rename函数copy&#xff08;&#xff09;函数…

【Android】视图与常用控件总结

文章目录 一、视图基础1.1 设置视图的宽高1.2 设置视图的间距1.3 设置视图的对齐方式1.4 总结 二、控件2.1 TextView2.1.1 设置宽高2.1.2 设置内容2.1.3 设置大小2.1.4 设置颜色 2.2 Button2.3 EditText2.4 ImageView2.5 ProgressBar2.6 AlertDialog2.7 ProgressDialog 本文主要…

EVM-MLIR:以MLIR编写的EVM

1. 引言 EVM_MLIR&#xff1a; 以MLIR编写的EVM。 开源代码实现见&#xff1a; https://github.com/lambdaclass/evm_mlir&#xff08;Rust&#xff09; 为使用MLIR和LLVM&#xff0c;将EVM-bytecode&#xff0c;转换为&#xff0c;machine-bytecode。LambdaClass团队在2周…

RICHTEK立锜科技 WIFI 7电源参考设计

什么是WIFI 7? WiFi 7&#xff08;Wi-Fi 7&#xff09;是下一代Wi-Fi标准&#xff0c;对应的是IEEE 802.11将发布新的修订标准IEEE 802.11be –极高吞吐量EHT&#xff08;Extremely High Throughput &#xff09;。Wi-Fi 7是在Wi-Fi 6的基础上引入了320MHz带宽、4096-QAM、Mu…

手动构建线性回归(PyTorch)

import torch from sklearn.datasets import make_regression import matplotlib.pyplot as plt import random #1.构建数据 #构建数据集 def create_dataset():x,y,coefmake_regression(n_samples100,n_features1,random_state0,noise10,coefTrue,bias14.5)#将构建数据转换为张…

H3CNE(计算机网络的概述)

1. 计算机网络的概述 1.1 计算机网络的三大基本功能 1. 资源共享 2. 分布式处理与负载均衡 3. 综合信息服务 1.2 计算机网络的三大基本类型 1.3 网络拓扑 定义&#xff1a; 网络设备连接排列的方式 网络拓扑的类型&#xff1a; 总线型拓扑&#xff1a; 所有的设备共享一…

# Redis 入门到精通(九)-- 主从复制(1)

Redis 入门到精通&#xff08;九&#xff09;-- 主从复制&#xff08;1&#xff09; 一、redis 主从复制 – 主从复制简介 1、互联网“三高”架构 高并发高性能高可用 2、你的“Redis”是否高可用&#xff1f; 1&#xff09;单机 redis 的风险与问题 问题1.机器故障  现…

代码随想录算法训练营第九天 |LeetCode151.翻转字符串里的单词 卡码网:55.右旋转字符串

代码随想录算法训练营 Day 9 代码随想录算法训练营第九天 |LeetCode151.翻转字符串里的单词 卡码网&#xff1a;55.右旋转字符串 目录 代码随想录算法训练营前言LeetCode151.翻转字符串里的单词卡码网&#xff1a;55.右旋转字符串 一、LeetCode151.翻转字符串里的单词1.题目链…

[Cesium for Supermap] 加载3dTiles,点击获取属性

代码&#xff1a; // 设为椭球var obj [6378137.0, 6378137.0, 6356752.3142451793];Cesium.Ellipsoid.WGS84 Object.freeze(new Cesium.Ellipsoid(obj[0], obj[1], obj[2]));var viewer new Cesium.Viewer(cesiumContainer);var scene viewer.scenescene.lightSource.ambi…

python 打包

#导出依赖文件列表 pip freeze > requirements.txt #安装对应文件 pip install -r requirements.txt #将依赖打成对应whl文件 pip wheel --wheel-dir ./dist -r ./requirements.txt #安装whl文件 pip install …whl

个人简约低调主页,三种主题风格源码

一、源码描述 这是一款简约低调的个人主页源码&#xff0c;提供了数百个精美的动画效果&#xff0c;拥有完美的视觉体验和交互体验&#xff0c;可操作性也达到了巅峰&#xff0c;源码支持三种主题风格&#xff0c;白色、黑色和蓝色渐变&#xff0c;所有这些效果都是通过原生Ja…

怎么压缩视频文件?简单的压缩视频方法分享

视频已成为我们日常生活中不可或缺的一部分。但随着视频质量的提高&#xff0c;文件大小也逐渐成为我们分享的阻碍。如何有效压缩视频文件&#xff0c;使其既能保持清晰&#xff0c;又能轻松分享&#xff1f;今天&#xff0c;给大家分享五种实用的视频压缩方法&#xff0c;快来…

Spring Boot 笔记1(启动类与控制器)

采用Spring Tool Suit 4 java jdk 17 学习启动类与控制器 创建Spring Starter Project 如果https://start.spring.io链接无效&#xff0c;可以选择https://start.aliyun.com 项目结构 启动类 启动类是程序的执行入口 例子1 Demo1Application.java package com.example.dem…

《从C/C++到Java入门指南》- 9.字符和字符串

字符和字符串 字符类型 Java 中一个字符保存一个Unicode字符&#xff0c;所以一个中文和一个英文字母都占用两个字节。 // 计算1 .. 100 public class Hello {public static void main(String[] args) {char a A;char b 中;System.out.println(a);System.out.println(b)…

Django cursor()增删改查和shell环境执行脚本

在Django中&#xff0c;cursor()方法是DatabaseWrapper对象&#xff08;由django.db.connectio提供&#xff09;的一个方法&#xff0c;用于创建一个游标对象。这个游标对象可以用来执行SQL命令&#xff0c;从而实现对数据库的增删改查操作。 查询&#xff08;Select&#xff0…

对象存储解决方案:高性能分布式对象存储系统MinIO

文章目录 引言I 自动化数据管理界面1.1 图形用户界面:GUI1.2 命令行界面:MinIO CLI1.3 应用程序编程接口:MinIO APIII 部署集成2.1 建议使用RPM或DEB安装方式2.2 创建环境变量文件2.3 启动MinIO服务2.4 将NGINX用作反向代理,配置负载。III 基础概念3.1 为什么是对象存储?3…

Python入门------pycharm加载虚拟环境

pycharm虚拟环境配置&#xff1a; 在按照前面的办法&#xff0c;配置好虚拟环境后,如果我们需要到虚拟环境开发&#xff0c;就需要给编译器配置虚拟环境 1.打开编译器&#xff0c;点击右下角的interpreter选项 2. 点击ADD Interpreter,添加虚拟环境 3. 因为我们使用的是原始…

CUDA编程00 - 配置CUDA开发环境

第一步&#xff1a; 在一台装有Nvidia显卡和驱动的机器上&#xff0c;用nvidia-smi命令查看显卡所支持cuda版本 第二步&#xff1a; 到Nvidia官网下载CUDA Toolkit并安装&#xff0c;CUDA Toolkit Archive | NVIDIA Developer 安装时按提示下一步即可&#xff0c;安装完成用 …