【C++之语法篇002】

C++学习笔记---002

  • C++知识语法篇
    • 1、缺省参数
      • 1.1、什么是缺省参数?
      • 1.2、缺省参数分类
      • 1.3、缺省参数的总结
    • 2、函数重载
      • 2.1、什么是函数重载?
      • 2.2、C支持函数重载?
      • 2.3、那么对于函数重载,函数名相同该如何处理?
      • 2.4、那么C++是如何支持重载?
    • 3、引用
      • 3.1、什么是引用?
      • 3.2、引用可做参数
      • 3.3、引用的特性
      • 3.4、引用和指针的关系
      • 3.5、常引用
      • 3.6、引用的作用
      • 3.7、野引用
      • 3.8、引用的总结

C++知识语法篇

前言:
前篇内容对于C++有一个基本认识,这篇文章开始将学习C++与C语言优化后的语法知识部分。
/知识点汇总/

1、缺省参数

1.1、什么是缺省参数?

概念
缺省参数是用来声明或定义函数时为函数的参数指定一个缺省值。
在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

#include <iostream>
void Func(int a = 0)//缺省参数(形参)
{std::cout << a << std::endl;
}
int main()
{Func();//0,没有传参时,使用参数的默认值Func(10);//10,传参数时,使用指定的实参return 0;
}

1.2、缺省参数分类

1.全缺省参数
2.半缺省参数
另外,比如有三个参数,却只传了一个或两个参数,称为半缺省参数。否则,三个参数全是缺省参数时,称为全缺省参数
值得注意的是,对于多参数的传参时。不能隔开/条约的传参,需从左向右的进行传参。

#include <iostream>
void Func(int a = 1, int b = 2, int c = 3)//缺省参数(形参)
{std::cout << a << std::endl;std::cout << b << std::endl;std::cout << c << std::endl << std::endl;//endl等价于'\n'
}
int main()
{Func();//1,2,3,没有传参时,使用参数的默认值Func(10,20);//10,20,传参数时,使用指定的实参Func(10, 20,30);//不能隔开/条约的传参,需从左向右//Func(, 10, 20);//Func(, , 20);//Func(10, , 20);return 0;
}

1.3、缺省参数的总结

1.缺省参数只能在声明给,而不是在定义时给。否则,编译就会报错,语法参数不匹配
2.所有带缺省的参数必须放在参数列表的右侧,即先定义所有的非缺省参数,再定义缺省参数
3.缺省参数在公共头文件包含的函数声明中指定,不要在函数的定义中指出(如果在函数的定义中指定缺省参数值,在公共头文件包含的函数声明中不能再次指定缺省参数值)
4.缺省参数并不一定是常量表达式,可以是任意表达式,甚至可以通过函数调用给出。如果缺省实参是任意表达式,则函数每次被调用时该表达式被重新求值。但是表达式必须有意义
5.C语言不支持,但C++兼容C
6.实参个数可以与形参不同,即,半缺省和全缺省参数

2、函数重载

前言:自然言语中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。

2.1、什么是函数重载?

概念
函数重载是一种特殊情况,C++允许在同一作用域中声明几个类似的同名函数,
但是注意这些同名函数的形参列表(参数个数,类型,顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。

在C++中不仅函数可以重载,运算符也可以重载。
例如:运算符 << , >> 。既可以做移位运算符,也可以做输出,输入运算符。
注意:重载函数的参数个数,参数类型或参数顺序三者中必须有一个不同

2.2、C支持函数重载?

C语言中,不允许函数名相同,所以不支持
C++中,允许函数名相同,支持重载,但有一定的要求
要求:函数名相同时,需要参数类型不同,构成函数重载。
C++函数重载要求的参数不同,一般有三种形式
1.参数类型不同;
2.参数顺序不同(本质还是类型不同);
3.参数个数不同。

举个直观的例子:

#include <iostream>
using namespace std;
int Add(int x, int y)
{cout << "int Add(int x, int y)" << endl;return x + y;
}
double Add(double m, double n)
{cout << "double Add(double m, double n)" << endl;return m + n;
}
void Add(double a, int b)
{cout << "void Add(double a, int b)" << endl;
}
int main()
{Add(1, 2);Add(1.01, 2.02);Add(1.001, 2);return 0;
}

2.3、那么对于函数重载,函数名相同该如何处理?

对于这个问题,不妨回顾一下,底层的编译过程,方便理解。
预处理、编译、汇编、链接分析
以栈的声明和定义为例:stack.h stack.c main.c

执行过程功能指令生成的文件
预处理展开头文件、宏替换、条件编译、去掉注释-E stack.i main.imain.i
编译语法、词法分析,检查语法,生成汇编代码-S stack.s main.smain.s
汇编把汇编翻译成二进制机器语言,生成目标文件-c stack.o main.omain.o
链接匹配符号表,结合目标文件(动态/静态链接),生成可执行程序main.exe

其中链接过程的关键:符号表 --> 匹配: 函数名和函数地址

另外从函数的栈帧与销毁的角度分析,汇编中call 函数名、函数名地址(就是执行函数的入口地址,第一条语句的地址),类比数组,数组名就是首元素地址,本质就是执行对应的指令
补充
程序中当函数有定义了,才会有函数入口地址。说明只有声明时,是没有函数的地址。只有定义没有声明,即:就是有地址没有call也是不行的。
简述:声明是承诺,定义是兑现,相辅相成的关系

所以对于这个问题可知,C语言不支持重载,因为链接时,直接用函数名去找地址,有同名函数,区分不开。

2.4、那么C++是如何支持重载?

而且当函数的声明和定义分开在不同文件时,怎么分辩?不得不提出C++对于C语言进行的优化,函数名修饰规则
C++链接过程也会生成一个符号表,符号表里除了函数名,还存着函数的修饰名,修饰名记录保存着函数的地址。
在调用函数时,编译器会通过符号表里查看修饰名来得到函数的地址实现调用
本质就是把参数带入进行修饰,完成函数名修饰规则,实现符号表的查表,解决函数名相同的处理。
但是请注意,对于不同的编译器,底层的规范有所不同,但原理相同

为了方便理解,就以典型的Linux中的链接举例。
比如典型的linux环境下,是以_Znntt…(可这样理解:_Z是格式+n是函数名长度+n(函数名name)+tt…(1个/多个参数的类型type))格式的函数名修饰规则

int Add(int x, int y);
double Add(double m, double n);
void Add(double a, int b);
int A(int x, int y);
int main()
{//转汇编观察Add(1, 2);//call _Z3AddiiAdd(1.01, 2.02);//call _Z3AddddAdd(1.001, 2);//call _Z3AdddiA(1, 2);//call _Z1Aiireturn 0;
}

再了解一下同样的代码,比如Vs2019环境下,是以 ?n@@YAttt@Z(理解记忆:?格式+n(函数名name)+@@YA格式+ttt…(返回值类型+参数类型)+@Z格式)

int Add(int x, int y);
double Add(double m, double n);
void Add(double a, int b);
void A(int x, int y);int main()
{Add(1, 2);//call   ?Add@@YAHHH@ZAdd(1.01, 2.02);//call ? Add @@YA NNN @ZAdd(1.001, 2);//call ? Add @@YA XNH @ZA(1, 2);//call ? A @@YA XHH @Zreturn 0;
}
char --- D
int ---- H
double --- N
void --- X
.....

在这里插入图片描述

3、引用

3.1、什么是引用?

概念
引用不是新定义一个变量,而是给已存在的变量起一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
所以改变引用(别名)的值,就可以改变原变量的值

格式:类型&引用变量名(C++称为对象名) = 引用实体

int a = 10;
int& b = a;
b = 20;  --->  a=b=20

举例

#include <iostream>
using namespace std;
int main()
{int a = 0;//引用,b就是a的别名int& b = a;cout << &b << endl;cout << &a << endl;b++;a++;int& c = a;int& d = c;d++;return 0;
}

3.2、引用可做参数

引用常见于作为参数使用。

#include <iostream>
using namespace std;
void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}
// 引用做参数
void Swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}
int main()
{int x = 0;int y = 1;Swap(&x, &y);Swap(x, y);return 0;
}

3.3、引用的特性

1.引用必须初始化
2.引用无法改变指向,所以无法完全替换指针

#include <iostream>
using namespace std;
int main()
{int a = 0;//1.引用必须初始化//int& b;//b = c;//2.引用定义后,不能改变指向int& b = a;int c = 2;b = c;//这句是赋值,并不是改变指向//3.一个变量可以有多个引用,多个别名int& d = b;return 0;
}

3.4、引用和指针的关系

指针和引用的功能是类似的,存在重叠性的;
C++的引用,对指针使用比较复杂的场景下能更好的进行替换,让代码更间接易理解,但是不能完全替代掉指针。
引用不能完全替代指针的原因:引用定义后,不能改变指向。
比如典型的链表,指针可以指向下一个结点,上一个结点,而引用无法改变其指向

#include <iostream>
using namespace std;
struct Node
{struct Node* next;struct Node* prev;int val;
};
//一级指针
void Pushback(struct Node* phead, int x)
{phead = newnode;
}
//对比 
//二级指针
void Pushback(struct Node** phead, int x)
{*phead = newnode;
}
//引用
void Pushback(struct Node*& phead, int x)
{phead = newnode;
}
int main()
{struct Node* plist = NULL;return 0;
}
#include <iostream>
using namespace std;
typedef struct Node
{struct Node* next;struct Node* prev;int val;
}Node,*PNode;//对比:二级指针和typedef+引用
void Pushback(Node** phead, int x)
{*phead = newnode;
}
void Pushback(PNode& phead, int x)
{phead = newnode;
}
int main()
{PNode plist = NULL;return 0;
}

3.5、常引用

const对引用变量的影响。

void text()
{const int a = 10;//int& ra = a;   //编译出错,a是常量const int& ra = a;//int& b = 10;  //编译出错,b是常量const int& b = 10;double d = 12.34;//int& rd = d;   //编译出错,类型不同const int& rd = d;
}

3.6、引用的作用

1.引用作为参数(a.输出型参数,b.作为传出参数,对象比较大时,可明显减少拷贝,提高效率)
2.引用做返回值(a.修改返回对象,b.减少拷贝,提高效率)

void Swap(int& a, int& b);
int* preorderTreversal(struct TreeNode* root, int* returnSize);
int* preorderTreversal(struct TreeNode* root, int& returnSize);

对象比较大时,可明显减少拷贝,提高效率
指针也可以,引用这种场景更据性价比

#include <iostream>
#include <time.h>
using namespace std;struct A
{ int a[100000]; 
};
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void main()
{A a;// 以值作为函数参数size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc1(a);size_t end1 = clock();// 以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc2(a);size_t end2 = clock();// 分别计算两个函数运行结束后的时间cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

3.7、野引用

类似于局部变量,返回变量出了函数作用域其生命周期就结束了,那么就不能用引用返回变量数据。
那么什么时候使用可以用引用返回?
1.static修饰变量 --静态变量
2.全局变量
3.堆区的变量

#include <iostream>
using namespace std;
//int func()
//{
//	int a = 0;
//	return a;
//}
//返回a的别名,但是此时函数结束后栈区上会销毁,那么去访问a属于非法访问,形成野引用。
//非法访问导致随机值。
int& func()
{int a = 0;return a;
}
int& fun()
{int a = 0;return a;
}
int main()
{int ret = func();//开辟一个整型空间//语法概念上引用就是一个别名,没有独立空间//int& ret = func();//并且此时给a的别名起了一个别名。导致两次非法访问,野引用。cout << "ret = " << ret << endl;fun();cout << "ret = " << ret << endl;return 0;
}

语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

纯C++写法:引出:1.结构体中可直接定义函数。2.引用作返回值

#include <iostream>
#include <assert.h>
using namespace std;
//C++ 结构体 == 类
struct SeqList
{//成员变量int* a;int size;int capacity;//成员函数void Init(){a = (int*)malloc(sizeof(int) * 4);size = 0;capacity = 0;}void PushBack(int x){//判容量if (size == capacity){int newcapacity = capacity == 0 ? 4 : capacity * 2;int* tmp = (int*)realloc(a, sizeof(int) * newcapacity);if (tmp == NULL){perror("realloc fail");return;}a = tmp;capacity = newcapacity;}a[size++] = x;capacity--;}//引用别名,结合了SLModity和SLGet//由此可见:引用别名具备双重功能int& SLGet(int pos){assert(pos >= 0);assert(pos < size);return a[pos];}//提前了解C++更优的写法;int& operator[](int pos){assert(pos >= 0);assert(pos < size);return a[pos];}
};
int main()
{SeqList s;s.Init();s.PushBack(1);s.PushBack(2);s.PushBack(3);s.PushBack(4);for (int i = 0; i < s.size; i++){//cout << "SLGet=" << s.SLGet(i) << endl;cout << "SLGet=" << s[i] << endl;//等价原型://cout << "SLGet=" << s.operator[](i) << endl;}cout << endl;for (int i = 0; i < s.size; i++){//if (s.SLGet(i) % 2 == 0)//{//	s.SLGet(i) *= 2;//}if (s[i] % 2 == 0){s[i] *= 2;}}for (int i = 0; i < s.size; i++){//cout << "SLGet=" << s.SLGet(i) << endl;cout << "SLGet=" << s[i] << endl;//等价原型://cout << "SLGet=" << s.operator[](i) << endl;}cout << endl;free(s.a);return 0;
}

3.8、引用的总结

(1).引用和指针的区别:

1.在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
2.在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

(2).引用和指针的不同点:

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

(3)引用的作用:

1.引用作为参数(a.输出型参数,b.作为传出参数,对象比较大时,可明显减少拷贝,提高效率)
2.引用做返回值(a.修改返回对象,b.减少拷贝,提高效率)

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

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

相关文章

QGis软件 —— 3、QGis创建形状图层点、通过xlsx及csv加载点

(方式一 ) 通过QGis创建形状图层点 1、如下gif&#xff0c;演示了创建形状图层 2、如下gif&#xff0c;演示了在高德地图上&#xff0c;形状图层上添加点 3、如下gif&#xff0c;演示了对形状图层点查看详细信息 4、如下gif&#xff0c;演示了对形状图层点查看属性表&#xff0…

生成式 AI - Diffusion 模型的数学原理(2)

来自 论文《 Denoising Diffusion Probabilistic Model》&#xff08;DDPM&#xff09; 论文链接&#xff1a; https://arxiv.org/abs/2006.11239 Hung-yi Lee 课件整理 文章目录 一、基本概念二、VAE与Diffusion model三、算法解释四、训练过程五、推理过程 一、基本概念 Diff…

代码随想录算法训练营第15天—二叉树04 | ● *110.平衡二叉树 ● *257. 二叉树的所有路径 ● 404.左叶子之和

*110.平衡二叉树 题目链接/文章讲解/视频讲解&#xff1a;https://programmercarl.com/0110.%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91.html 考点 后序遍历二叉树高度计算 我的思路 错误地将平衡二叉树的定义等价为判断整体二叉树的最大深度和最小深度之差是否大于1 视…

Redis系列学习文章分享---第一篇(Redis快速入门之初始Redis--NoSql+安装redis+客户端+常用命令)

目录 今天开始进入Redis系列学习分享1.初识Redis1.1.认识NoSQL1.1.1.结构化与非结构化1.1.2.关联和非关联1.1.3.查询方式1.1.4.事务1.1.5.总结 1.2.认识Redis1.3.安装Redis1.3.1.依赖库1.3.2.上传安装包并解压1.3.3.启动1.3.4.默认启动1.3.5.指定配置启动1.3.6.开机自启 1.4.Re…

【MySQL】变量、流程控制

一、变量 在MySQL的存储过程与函数中&#xff0c;可以使用变量来存储查询或计算的中间结果数据&#xff0c;或者输出最终的结果数据。它可以分为用户自定义变量与系统变量 1、系统变量 1&#xff09;系统变量分为全局变量&#xff08;需要使用关键字global&#xff09;和会话…

【前端素材】bootstrap5实现房产信息网HomeFi平台(附源码)

一、需求分析 房产信息网是一个在线平台,专门提供房地产相关信息的网站。这些网站通常为买家、卖家、租客、房地产经纪人等提供各种房产信息,包括可售房屋、出租房源、房价走势、地产市场分析、房产投资建议等内容。以下是房产信息网的主要功能和特点: 房源信息浏览:用户可…

【lesson60】网络基础

文章目录 网络发展认识协议网络协议初识OSI七层模型TCP/IP五层(或四层)模型网络传输基本流程数据包封装和分用网络中的地址管理 网络发展 以前没有网络剧的工作模式是&#xff1a;独立模式:&#xff0c;计算机之间相互独立 所以多个计算机要协同开发比较难。 有了网络以后&am…

6.s081 学习实验记录(九)lock parallelism

文章目录 一、Memory allocator简介提示实验代码实验结果 二、Buffer cache简介提示实验代码实验结果 该实验将重构某些代码以提高并发度。 首先切换到lock分支&#xff1a; git fetchgit checkout lockmake clean 一、Memory allocator 简介 user/kalloctest 这个程序会对…

关于投资,房地产,AI

各位朋友&#xff0c;新年好&#xff01; 过个年&#xff0c;世界发生了很多大事&#xff01; 投资 先是证监会&#xff0c;证监会年前换帅&#xff0c;吴清接棒&#xff0c;吴清何许人也&#xff1f;江湖人称“券商屠夫”&#xff0c;成功处置了2008年的券商风险&#xff0…

Eclipse - Format Comment

Eclipse - Format & Comment 1. Correct Indentation2. Format3. Toggle Comment4. Add Block Comment5. Remove Block CommentReferences 1. Correct Indentation Ctrl A: 选择全部代码 Ctrl I: 校正缩进 or right-click -> Source -> Correct Indentation 2. F…

【开工大吉】推荐4款开源、美观的WPF UI组件库

WPF介绍 WPF 是一个强大的桌面应用程序框架&#xff0c;用于构建具有丰富用户界面的 Windows 应用。它提供了灵活的布局、数据绑定、样式和模板、动画效果等功能&#xff0c;让开发者可以创建出吸引人且交互性强的应用程序。 HandyControl HandyControl是一套WPF控件库&#xf…

安全技术和防火墙

1.安全技术和防火墙 1.1安全技术 入侵检测系统&#xff08;Intrusion Detection Systems&#xff09;&#xff1a;特点是不阻断任何网络访问&#xff0c;量化、定位来自内外网络的威胁情况&#xff0c;主要以提供报警和事后监督为主&#xff0c;提供有针对性的指导措施和安全决…

普中51单片机学习(九)

蜂鸣器 蜂鸣器简介 在单片机应用的设计上&#xff0c;很多方案都会用到蜂鸣器&#xff0c;大部分都是使用蜂鸣器来做提示或报警&#xff0c;比如按键按下、开始工作、工作结束或是故障等等。改变单片机引脚输出波形的频率&#xff0c;就可以调整控制蜂鸣器音调&#xff0c;产…

Python操作Kafka基础教程

01 Python操作Kafka基础教程 创建ZooKeeper容器 docker run -d --name zookeeper -p 2181:2181 -v /etc/localtime:/etc/localtime wurstmeister/zookeeper创建Kafka容器 语法是&#xff1a; docker run -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID0 -e KAFKA_ZOOKE…

世界顶级名校计算机专业,都在用哪些书当教材?(文末送书)

目录 01《深入理解计算机系统》02《算法导论》03《计算机程序的构造和解释》04《数据库系统概念》05《计算机组成与设计&#xff1a;硬件/软件接口》06《离散数学及其应用》07《组合数学》08《斯坦福算法博弈论二十讲》参与规则 清华、北大、MIT、CMU、斯坦福的学霸们在新学期里…

讨好型人格的职业分析,如何改变讨好型人格

一味讨好他人&#xff0c;忽略自己感受&#xff0c;凡事以人为先&#xff0c;忽视自己需求&#xff0c;这就是讨好型人格。 讨好型人格最典型的表现就是非常注重外界的看法&#xff0c;不管做什么事都会小心翼翼&#xff0c;生怕自己所做的事会引发别人的不满。 如果自己哪方…

MAC电脑系统清理空间免费版软件CleanMyMac X2024

大家好&#xff0c;我是那个总是被苹果电脑“内存已满”提示搞得焦头烂额的专业博主。如果你也像我一样&#xff0c;在使用Mac时经常遭遇卡顿、慢吞吞的情况&#xff0c;那么今天的Mac清理空间妙招分享绝对适合你&#xff01; CleanMyMac X全新版下载如下: https://wm.makedi…

【Redis快速入门】深入解读哨兵模式

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

HTML 入门指南

简述 参考&#xff1a;HTML 教程- (HTML5 标准) HTML 语言的介绍、特点 HTML&#xff1a;超级文本标记语言&#xff08;HyperText Markup Language&#xff09; “超文本” 就是指页面内可以包含图片、链接等非文字内容。“标记” 就是使用标签的方法将需要的内容包括起来。…

电阻(二):希尔伯特(Hilbert)曲线

1、Hilbert简介 希尔伯特曲线是一种能在 2D平面完美填充正方形的曲线&#xff0c;连续且稳定&#xff08;当细分足够小时&#xff0c;线构成面&#xff09;而又不可导的曲线。只要恰当选择函数&#xff0c;画出一条连续的参数曲线&#xff0c;当参数 t 在 [0、1 ] 区间取值时&a…