C++入门(中篇)

这篇具有很好参考价值的文章主要介绍了C++入门(中篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🔥🔥本章重内容
C++入门(中篇)

1. 函数重载

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

#include <iostream>
using namespace std;

void Add(int a, int b)
{
	cout << a + b << endl;
}

void Add(double a, double b)
{
	cout << a + b << endl;
}

int main()
{
	Add(1, 2);
	Add(1.1, 2.2);
	return 0;
}

上面这段代码在C语言中肯定是编不过去的,C语言会报错说,函数重命名
但是C++支持这样写,只要函数的 (参数个数 或 类型 或 类型顺序) 不同就可以。

//参数类型不同
void Add(int a, int b)
{
	cout << a + b << endl;
}

void Add(double a, double b)
{
	cout << a + b << endl;
}

//参数个数不同
void fun()
{
	cout << "fun()" << endl;
}

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

//参数顺序不同
void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
	cout << "f(char b, int a)" << endl;
}

C++是怎么支持函数名重载的呢?

C++中有函数名修饰规则,但是这个规则不是C++创始人给的,是由写编译器的人来给的,所以Linux与Windows的函数名修饰规则是不同的。
函数名修饰规则会给函数另起一个名字,简单的了解一下汇编代码。
C++入门(中篇)
图中箭头是main函数中对应的指令,call的意思是跳转到被调用的函数那里,可以看到两次call他们的地址是不同的,所以C++允许函数名相同,但(参数个数 或 类型 或 类型顺序)不能相同。
看一下输出结果:
C++入门(中篇)
注意:如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。

2.引用

引用就相当于是起别名,相当于你的大名和小名,它都指的是你。

//类型& 引用变量名(对象名) = 引用实体;
void fun()
{
	int a = 10;
	int& ra = a;//<====定义引用类型
	printf("%p\n", &a);
	printf("%p\n", &ra);
}

代码中的int& ra = a;就是对a的引用
既然是对a起别名那他们的地址相同吗?
如下图所示:
C++入门(中篇)
所以如果我们改变别名,原本的值也会发生改变。

注意引用类型必须和引用实体是同种类型的

2.1引用特性

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再不能引用其他实体
int main()
{
	//这样的代码是不行的
	int& b;

	//一个变量可以有多个引用
	int a = 0;
	int& c = a;
	int& d = a;

	//引用一旦引用一个实体,再不能引用其他实体
	int x = 5;
	int y = 6;
	int& z = x;
	int& z = y;//错误写法

	return 0;
}

前面两种好理解,讲一下后面这种为什么不行。

解释为什么引用一旦引用一个实体,再不能引用其他实体
当我们写了两个
int& z = ;
int& z = ;
编译器会认为 z 是重定义,进行了多次初始化。
就像我们写了两个 int a = ; int a = ;这样肯定是不行的。
如果我们写成
int& z = x;
z = y;
这相当于我们把y的值赋给了z
所以说:引用一旦引用一个实体,再不能引用其他实体

2.2常引用

什么是常引用呢,就是我们引用的是常量。
先来说结论,大家来判断下面的代码是否正确。
结论:引用过程中权限可以平移或缩小,但不能扩大。

int main()
{
	//问题一
	const int a = 10;
	int& ra = a;

	//问题二
	int b = 10;
	const int& rb = b;

	//问题三
	double d = 1.1;
	int& rd = d;
	return 0;
}

前两个问题大家都可以根据结论判断它是否正确。
问题一是错误的,因为它将a的权限扩大了,原本a是const的常量,我们在起别名的时候只能是常量别名。
问题二是正确的,我们说权限可以缩小或平移,所以别名可以加上const。
问题三呢?它是给一个double类型的变量d起别名,但别名的类型是int类型。
有的同学可能会说,给double类型的数据起别名只能用double类型。
那我们先来看结果。
C++入门(中篇)
为什么会有警告说是从“double”转换到“const int”呢?
C++入门(中篇)
所以会有上面那样的警告。
我们说权限可以缩小和平移,如果我们给int前加上const那么程序是不是就可以正常运行了?
C++入门(中篇)
答案是正确的。

2.3使用场景

1. 做参数

用引用参数,可以代替我们之前使用的指针。
列如我们要交换两个数的值

//指针写法
void Swap(int* left, int* right)
{
	int temp = *left;
	*left = *right;
	*right = temp;
}

//引用写法
void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}

我们发现引用使用起来更方便,使用指针有时候我们可能还会传值错误,忘记传地址过去。
但我们使用引用的话,根本不需要去考虑传地址的问题。
引用直接给变量起别名,使用起来更方便。

2. 做返回值

那我们先来回忆一下之前C语言用类型做返回值。
C++入门(中篇)
如果返回值的内存占用大,我们直接返回引用值。
如果是返回引用的话,可以直接跳过拷贝,赋值给a。减少时间和空间的使用。
那我们以后是所有带返回值的函数都要用引用返回吗?
当然不是。
就比如上面那段代码如果用引用值返回的话,会带来后果呢?
C++入门(中篇)
图片中的输出结果看似没有问题,但实际是有问题的。
我们返回c的别名,但函数调用结束后,栈帧会被销毁,空间会被释放掉。

这里打印ret的值是不确定的
如果Count函数结束,栈帧销毁,没有清理栈帧,那么ret的结果侥幸是正确的
如果Count函数结束,栈帧销毁,清理栈帧,那么ret的结果是随机值

当我们再调用依次其他函数,或再多写几行代码,之前的函数的数据会被覆盖。
那怎么证明呢?
我们用引用来接收返回值。相当于是返回值的别名。
C++入门(中篇)
因为a是返回值的别名,所以后面再调函数,会改变a的值。
C++入门(中篇)
当我们调用其它函数后,它会覆盖掉当前的函数。所以a会变为随机值。
C++入门(中篇)
注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用
引用返回,如果已经还给系统了,则必须使用传值返回。

2.4引用和指针的区别

在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。(他们的地址相同我们有证明过)。
在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

int main()
{
	int a = 10;

	int& ra = a;
	ra = 20;

	int* pa = &a;
	*pa = 20;
	return 0;
}

C++入门(中篇)
可以看到引用的汇编代码与指针的汇编代码是相同的,所以引用也会开辟一个指针的空间
32位平台下开4个字节,64位平台下开8个字节

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

3.内联函数

内联函数是怎么来的呢?
我们先看一段代码。

void Print(int i)
{
	cout << i << endl;
}

int main()
{
	for (int i = 0; i < 100; i++)
	{
		Print(i);
	}
	return 0;
}

这个函数会被调用100次,函数调用建立栈帧的开销会比较大。
而内联函数是在调用函数时直接在被调用的位置上展开的,不会开辟栈帧。
只需要在函数前加一个inline。这个函数就可能会成为内联函数。

//内联函数写法
inline void Print(int i)
{
	cout << i << endl;
}

C++入门(中篇)
在我们看汇编代码时,它为什么还是会call(调用函数)呢?
因为我们在debug版本下,debug模式下,编译器默认不会对代码进行优化。
但我们也可以对其进行修改,使inline可以在debug版本下进行优化。
C++入门(中篇)

C++入门(中篇)
C++入门(中篇)
修改完成之后便可以观察汇编代码,看其是否以优化。
C++入门(中篇)
所以这就是内联函数的优点,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。
既然内联函数没有函数调用建立栈帧的开销,又可以提升运行效率那我们是不是应该全去使用内联函数呢?
C++入门(中篇)
如果我们都去使用内敛函数的话,上图会产生1000 * 50行代码,
不用内联函数的话就只会有1000行调用代码和20行Add的代码。
所以如果函数内容代码量大的话,我们就不能使用内联函数。

如果函数内代码行数大于10,我们就不能使用内联函数。

使用内联函数还需要注意一个点,就是内联函数的声明和定义必须放在一起。
C++入门(中篇)
C++入门(中篇)
C++入门(中篇)
如果像我们这样写程序是过不去的。
因为内联函数是没有地址的,当我们链接时发现找不到fun函数,内联函数不会函数名修饰。
C++入门(中篇)

所以我们要把内联函数的定义与声明放在一起写。
当我们把声明和定义都写在头文件里时,程序就可以链接上了。
C++入门(中篇)

特性

  1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。
  2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。
  3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到

C++入门(中篇)文章来源地址https://www.toymoban.com/news/detail-424639.html

到了这里,关于C++入门(中篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++之类和对象的中篇

    𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary_walk       ⸝⋆   ━━━┓      - 个性标签 - :来于“云”的“羽球人”。 Talk is cheap. Show me the code ┗━━━━━━━  ➴ ⷯ 本人座右铭 :   欲达高峰,必忍其痛;欲戴王冠,必承其重。 👑💎💎👑

    2024年04月18日
    浏览(26)
  • 【入土级】详解C++类&对象(中篇)

    目录 前言:类的6个默认成员函数 一, 构造函数 1. 概念 2. 特性 二, 析构函数 2.1 概念 2.2 特性 2.3 牛刀小试  三, 拷贝构造函数 3.1概念 3. 2 特点 四, 赋值运算符重载 4. 1 运算符重载  五, const成员函数 六,取地址及const取地址操作符重载 七,练习——实现日期计算器

    2024年02月05日
    浏览(34)
  • 重生c++系列之类与对象(中篇)

    好的继上期,我们今天带来c++类与对象系列的继续学习。 如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员 函数。 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为

    2024年02月11日
    浏览(29)
  • C++好难(3):类和对象(中篇)

    类的6个默认成员函数 构造函数 析构函数 拷贝构造函数 赋值运算符重载 const成员函数 取地址及const取地址操作符重载 目录 【本章目标】 1.类的6个默认成员函数 2.构造函数 2.1概念 2.2构造函数的特性 特性一 特性二 特性三 特性四 特性五 特性六 特性七 2.3总结 3.析构函数 3.

    2024年02月03日
    浏览(28)
  • 【C++深入浅出】初识C++中篇(引用、内联函数)

      目录 一. 前言 二. 引用 2.1 引用的概念 2.2 引用的使用 2.3 引用的特性 2.4 常引用 2.5 引用的使用场景 2.6 传值、传引用效率比较 2.7 引用和指针的区别  三. 内联函数 3.1 内联函数的概念 3.2 内联函数的特性          上期说道,C++是在C的基础之上,容纳进去了 面向对象编程

    2024年02月12日
    浏览(29)
  • 【C++】类和对象(中篇)----->六大默认成员函数

    目录 一、类的6个默认成员函数 二、构造函数  1、概念   2、特性 三、析构函数  1、概念  2、特性 四、拷贝构造函数  1、概念  2、特征 五、赋值运算符重载  1、运算符重载  2、值运算符重载    2.1 赋值运算符重载格式    2.2 赋值运算符只能重载成类的成员函数不能

    2024年02月12日
    浏览(32)
  • SpringCloud Aliba-Sentinel【中篇】-从入门到学废【5】

    🎵歌词分享🎵 岁月在墙上剥落看见小时候。 ——《东风破》 目录 🥓1.流控规则 🌭2. 熔断规则 🧈3.热点规则  🧂4.系统规则  1. 资源名 :唯一名称,默认请求路径 2. 针对来源 : Sentinel可以针对调用者进行限流,填写微服务名,默认default (不区分来源) 3. 阈值类型/单机阈 值:

    2024年01月24日
    浏览(23)
  • 【C++深入浅出】类和对象中篇(六种默认成员函数、运算符重载)

    目录 一. 前言  二. 默认成员函数 三. 构造函数 3.1 概念 3.2 特性 四. 析构函数 4.1 概念 4.2 特性 五. 拷贝构造函数 5.1 概念 5.2 特性 六. 运算符重载 6.1 引入 6.2 概念 6.3 注意事项 6.4 重载示例 6.5 赋值运算符重载 6.6 前置++和后置++运算符重载 七. const成员函数 7.1 问题引入 7.2 定义

    2024年02月09日
    浏览(34)
  • Android启动流程优化 中篇

    本文链接:https://blog.csdn.net/feather_wch/article/details/131587046 1、我们可以优化部分 Application构建到主界面onWindowFocusChanged 2、启动方式(官方) 冷启动 热启动 温启动 3、怎么样算是卡顿? 卡顿:2-5-8原则 2秒以内:流程 2-5秒:可以接受 5-8秒:有些卡顿 8秒以上:非常卡顿,没办法接

    2024年02月12日
    浏览(38)
  • SpringMVC学习笔记--中篇

    重定向:当浏览器输入网址访问服务器时,服务器会返回另一个网址给浏览器,告诉浏览器,你用这个地址重新访问一下吧。典型的应用就是,网站迁移到新的服务器上了,但是老用户只知道旧的地址,这样就可以当用户访问旧地址时,通过重定向返回新的地址。 转发:当浏

    2024年02月16日
    浏览(14)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包