初遇C++之语法篇(完结)

news2024/11/23 20:33:01

🧃博客主页:阿博历练记
📖文章专栏:c++
🚍代码仓库:阿博编程日记
🍡欢迎关注:欢迎友友们点赞收藏+关注哦🌹

在这里插入图片描述

文章目录

    • 🍭1.函数重载
      • 📜1.1函数重载的概念
      • 📢1.2函数重载三大误区
      • 🍄1.3C++支持函数重载的原理--名字修饰
    • 🍧2.引用
      • 📜2.1引用概念
      • 🪄2.2引用使用场景:
      • 🔍2.3引用特性
      • 🧊2.4常引用
      • 🎃经典误区
      • 💌面试提问
    • 🥷3.内联函数
      • 📜3.1内联函数的概念
      • 📑3.2内联函数的特性
    • 👻4.auto关键字
      • 📜4.1auto简介
      • 🔖4.2auto不能推导的场景
    • 📔5.基于范围的for循环(C++11)
      • ❌误区
    • 🎨6.指针控制nullptr(C++11)

🍭1.函数重载

📜1.1函数重载的概念

函数重载:是函数的一种特殊情况,C语言不允许同名函数,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 类型类型顺序)不同,🚩🚩友友们注意这里不比较返回值常用来处理实现功能类似数据类型不同的问题.

1.参数类型不同

#include<iostream>
using namespace std;
int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;
	return left + right;
}
int main()
{
	cout << Add(1, 2) << endl;
	cout << Add(1.1, 2.2) << endl;
	return 0;
}

在这里插入图片描述

2.参数个数不同

#include<iostream>
using namespace std;
void f()
{
	cout << "f()" << endl;
}
void f(int a)
{
 cout << "f(int a)" << endl;
}
int main()
{
	f();
	f(10);
	return 0;
}

在这里插入图片描述
3.参数类型顺序不同

#include<iostream>
using namespace std;
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;
}
int main()
{
	f(10, 'a');
	f('a', 10);
	return 0;
}

在这里插入图片描述

📢1.2函数重载三大误区

❌误区一:

#include<iostream>
using namespace std;
void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
}
void f(int b, char a)
{
	cout << "f(int b, char a)" << endl;
}
int main()
{
	f(10, 'a');
	f('a', 10);
	return 0;
}

在这里插入图片描述

📝友友们注意,函数重载是类型顺序不同,而不是形参的名字顺序不同.

❌误区二:

#include<iostream>
using namespace std;
namespace  N1
{
	void func(int x)
	{

	}
}
namespace  N2
{
	void func(double x)
	{

	}
}
int main()
{
	return 0;
}

在这里插入图片描述

#include<iostream>
using namespace std;
namespace  N1
{
	void func(int x)
	{

	}
}
namespace  N2
{
	void func(int x)
	{

	}
}
int main()
{
	return 0;
}

在这里插入图片描述

🕵可能友友们会认为第①种构成函数重载,但是如果第一种构成重载的话,现在第②种很显然已经不是函数重载了,为什么程序还是可以编译通过呢,所以我们这里就可以从反面验证这里不构成函数重载,这里主要就是这两个函数不在同一个作用域里面,而函数重载要求在同一个作用域里面.

❌误区三:

#include<iostream>
using namespace std;
void Func(int a)
{
	cout << "void Func(int a)" << endl;
}
void Func(int a,int b=10)
{
	cout << "void Func(int a,int b)" << endl;
}
int main()
{
	/*Func(1);
	Func(1, 2);*/
	return 0;
}

在这里插入图片描述

💨💨友友们注意,这里构成函数重载,因为这两个函数参数的个数不同,与缺省参数没有关系.

#include<iostream>
using namespace std;
void Func(int a)
{
	cout << "void Func(int a)" << endl;
}
void Func(int a,int b=10)
{
	cout << "void Func(int a,int b)" << endl;
}
int main()
{
	Func(1);
	Func(1, 2);
	return 0;
}

在这里插入图片描述

🌟🌟虽然它们构成重载函数,但是在调用的时候会存在歧义,比如当实参只有1时,这两个函数都可以调用,编译器就不知道该调用谁了,所以就会产生调用不明确的报错.

🍄1.3C++支持函数重载的原理–名字修饰

在这里插入图片描述
① C语言程序
在这里插入图片描述
② C++程序

1.vs2022环境下
在这里插入图片描述
2.Linux环境下
在这里插入图片描述

🍧2.引用

📜2.1引用概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间,🔍引用类型必须和引用实体是同种类型的.

🪄2.2引用使用场景:

一.引用做参数

引用示例1:

1.传址交换

#include<iostream>
using namespace std;
void swap(int*x1,int*x2)
{
	int tmp = *x1;
	*x1 = *x2;
	*x2 = tmp;
}
int main()
{
	int a = 3;
	int b = 5;
	swap(&a, &b);
	cout << a << endl;
	cout << b << endl;
	return 0;
}

2.引用交换

#include<iostream>
using namespace std;
void swap(int&x1,int&x2)
{
	int tmp = x1;
	x1 = x2;
	x2 = tmp;
}
int main()
{
	int a = 3;
	int b = 5;
	swap(a, b);
	cout << a << endl;
	cout << b << endl;
	return 0;
}

所以友友们当我们使用引用之后,就可以不用指针了,因为x1就是a的别名,x2就是b的别名,所以它们两个就是a和b,我们只需要直接交换就可以了🤩🤩.

引用示例2:

1.二级指针

#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct
{
	int val;
	struct ListNode* next;
}ListNode;
void PushBack(ListNode**pphead,int x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->val = x;
	newnode->next = NULL;
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		//...
	}
}
int main()
{
	ListNode* plist = NULL;
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	return 0;
}

💬💬友友们对于这种情况,在我们没有使用引用之前,我们必须使用传址的方式,用二级指针接收,然后解引用才能改变plist,如果用一级指针接收的话,那么形参就是实参的一份临时拷贝,形参的改变不会影响实参,所以友友们这种方法是不是比较麻烦.🤦🤦

2.引用交换

#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct
{
	int val;
	struct ListNode* next;
}ListNode;
void PushBack(ListNode*&phead,int x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->val = x;
	newnode->next = NULL;
	if (phead == NULL)
	{
		phead = newnode;
	}
	else
	{
		//
	}
}
int main()
{
    ListNode* plist = NULL;
	PushBack(plist, 1);
	PushBack(plist, 2);
	PushBack(plist, 3);
	PushBack(plist, 4);
	return 0;
}

💌友友们这里phead就是plist的别名,所以它就是plist,所以改变phead就是改变plist,学完引用之后我们这里就可以不再用二级指针了.💯

二.引用做返回值

1.传值返回

#include<iostream>
#include<stdlib.h>
using namespace std;
int count()
{
    int n = 0;
	n++;
	// ...
	return n;
}
int main()
{
	int ret = count();
	return 0;
}

2.传引用返回

#include<iostream>
#include<stdlib.h>
using namespace std;
int& count()
{
    int n = 0;
	n++;
	// ...
	return n;
}
int main()
{
	int ret = count();
	//这里打印可能是1,也可能是随机值
	cout << ret << endl;
	return 0;
}

在这里插入图片描述
代码验证

#include<iostream>
#include<stdlib.h>
using namespace std;
int& count()
{
    int n = 0;
	n++;
	// ...
	return n;
}
int main()
{
	int &ret = count();
	//这里返回值可能是1,也可能是随机值
	cout << ret << endl;
	cout << ret << endl;
	return 0;
}

在这里插入图片描述

🍔知识小结:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

🔍2.3引用特性

1.引用必须在定义的时候初始化.
2.一个变量可以有多个引用,比如这里b,c,d都是a的引用.
在这里插入图片描述
3.引用一旦引用一个实体,再不能引用其它实体.
在这里插入图片描述

🧊2.4常引用

#include<iostream>
#include<stdlib.h>
using namespace std;
int main()
{
	const int a = 0;
	int x = 1;
	int& b = a;          //权限的放大
	const int& c = a;    //权限的平移
	const int& d = x;   //权限的缩小
	return 0;
}

📝友友们在引用过程中,权限可以平移缩小,但是不能放大.

🎃经典误区

误区①

#include<iostream>
#include<stdlib.h>
using namespace std;
int main()
{
	const int a = 0;
	int b = a;
	return 0;
}

📝这里b是a的赋值,把a的值拷贝给b,b的改变不会影响a,它和a根本不是一个变量,所以不涉及权限的放大.

误区②

#include<iostream>
#include<stdlib.h>
using namespace std;
int main()
{
	int i = 0;
	double& d = i;
	return 0;
}

🔔友友们这里注意,i是int类型,d是double类型,当i赋值给d时,这里会有隐式类型转换,这里会产生一个double类型的临时变量,临时变量具有常性不能修改,所以这里实质上是一种权限的放大,所以我们应该加一个const保持权限的平移才可以.

误区③

#include<iostream>
#include<stdlib.h>
using namespace std;
int func()
{
    int a = 0;
	return a;
}
int main()
{
	int& ret = func();
	return 0;
}

👑友友们注意这里是传值返回,这里不是用变量a返回,这里会生成一个临时变量,用临时变量返回然后再拷贝给ret,临时变量具有常性,不能修改,所以我们这里在引用的时候实质上也是权限的放大,所以我们要加上const保持权限的平移就可以了.

💌面试提问

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

🥷3.内联函数

📜3.1内联函数的概念

inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。

1.未用inline
在这里插入图片描述
2.使用inline

🔎查看方式

1. 在release模式下,查看编译器生成的汇编代码中是否存在call Add
2.在debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不会对代码进行优化,以下给出vs2013的设置方式)

在这里插入图片描述
在这里插入图片描述

📑3.2内联函数的特性

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

👻4.auto关键字

📜4.1auto简介

C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
注意:使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

#include<iostream>
#include<stdlib.h>
#include<vector>
#include<string>
using namespace std;
int main()
{
	int a = 0;
	auto b = a;
	auto c = &a;                  //普通场景没有价值,类型很长时很有价值,可以简化我们的代码
	auto& d = a;
	std::vector<std::string> v;
	std::vector<std::string>::iterator it = v.begin();
	auto it = v.begin();
	return 0;
}

友友们,这里我们也可以通过typeid看它们的类型🔍

int main()
{
	int a = 0;
	auto b = a;
	auto c = &a;                  //普通场景没有价值,类型很长时很有价值,可以简化我们的代码
	auto& d = a;
	std::vector<std::string> v;
	//std::vector<std::string>::iterator it = v.begin();
	auto it = v.begin();
	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
	cout << typeid(it).name() << endl;
	return 0;
}

在这里插入图片描述

🔖4.2auto不能推导的场景

1. auto不能作为函数的参数
void TestAuto(auto a)
{} ,此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导,比如我们实参传了一个3,编译器无法判断是整形3还是字符3.
2.auto不能直接用来声明数组
auto b[] = {4,5,6}; 这种情况也是不允许的,编译器也无法判断类型.

📔5.基于范围的for循环(C++11)

#include<iostream>
#include<stdlib.h>
using namespace std;
int main()
{
	int array[] = { 1, 2, 3, 4, 5 };
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
		array[i] *= 2;
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
		cout << array[i] << " ";
	cout << endl;
	for (auto e: array)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

🃏范围for循环会依次取数组中的数据赋值给e,自动判断结束,自动迭代.

在这里插入图片描述

友友们,这里我们对x乘以2,为什么打印出来的数据还是没有变化呢,🚩这里一定要注意,x是数组数据的拷贝,x的改变不会影响数组中的数据,所以我们需要加一个引用就可以了,此时x就是数组中数据的别名,就是数组中的数据,所以此时x的改变就会影响数组中的元素了.

❌误区

void TestFor(int array[])
{
    for(auto& e : array)
        cout<< e <<endl;
}

友友们,这种是不可以的,当使用范围for循环的时候,array那里必须是数组名,C++实际上只把形参数组名作为一个指针变量来处理,用来接收从 实参传过来的地址.

🎨6.指针控制nullptr(C++11)

using namespace std;
void f(int)
{
	cout << "f(int)" << endl;
}
void f(int*)
{
	cout << "f(int*)" << endl;
}
int main()
{
	f(0);
	f(NULL);
	f((int*)NULL);
	return 0;
}

在这里插入图片描述

友友们注意,在C++中,NULL的类型就不是指针类型了,我们如果要当成指针使用的话,需要强转类型
注意:
1.在C++中引入了一个关键字nullptr,在使用nullptr表示指针空值时,不需要包含头文件
2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
3.为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr

✨✨好了友友们,这期的内容到这里就告一段落了,下期不见不散.🪄🪄

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

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

相关文章

Nacos单节点部署

&#x1f388; 作者&#xff1a;互联网-小啊宇 &#x1f388; 简介&#xff1a; CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作&#xff0c;擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…

第十五章 定义 HL7 的 DTL 数据转换

文章目录 第十五章 定义 HL7 的 DTL 数据转换 第十五章 定义 HL7 的 DTL 数据转换 每个接口可能需要一定数量的数据转换。创建转换时&#xff0c;不要使用保留的包名称。 重要提示&#xff1a;请勿在数据转换中手动更改 HL7 转义序列&#xff1b;自动处理这些。 可以使用“数…

智能状态监测如何帮助设备管理团队转型升级?

制造业面临人才短缺和生产力提升的双重挑战。然而&#xff0c;全球市场对生产效率和产品质量的要求依然高企。这些挑战的核心在于&#xff0c;制造业需要在日益复杂的环境下&#xff0c;实时识别并应对生产过程中的异常情况&#xff0c;确保生产持续稳定。 一、传统状态监测的限…

Android 13 Hotseat定制化修改

一.背景 由于需求是需要自定义修改Hotseat,所以此篇文章是记录如何自定义修改hotseat的,应该可以覆盖大部分场景,修改点有修改hotseat布局方向,hotseat图标数量,hotseat图标大小,hotseat布局位置,hotseat图标禁止形成文件夹,hotseat图标禁止移动到Launcher中,下面开始…

深度学习中的优化算法

文章目录 前言一、优化和深度学习1.1 优化的目标1.2 深度学习中的优化挑战1.2.1 局部最小值1.2.2 鞍点1.2.3 梯度消失 二、梯度下降2.1 一维梯度下降2.1.1 学习率 2.2 多元梯度下降2.3 自适应方法2.3.1 牛顿法2.3.2 其他自适应方法 三、随机梯度下降3.1 随机梯度更新3.2 动态学…

JS逆向之顶像滑块

本教程仅限于学术探讨&#xff0c;也没有专门针对某个网站而编写&#xff0c;禁止用于非法用途、商业活动、恶意滥用技术等&#xff0c;否则后果自负。观看则同意此约定。如有侵权&#xff0c;请告知删除&#xff0c;谢谢&#xff01; 目录 一、接口请求流程 二、C1包 三、ac 四…

HTTP协议学习笔记1

初识HTTP 输入网址进入网页过程发生了什么&#xff1f; DNS解析&#xff1a;浏览器会向本地DNS服务器发出域名解析请求&#xff0c;如果本地DNS服务器中没有对应的IP地址&#xff0c;则会向上级DNS服务器继续发出请求&#xff0c;直到找到正确的IP地址为止。 建立TCP连接&…

关于Log日志

日志常用的如Logback&#xff0c;方便查看日志和打印的SQL&#xff08;或配合idea的一些mybaits日志插件&#xff09;&#xff0c;简单讲讲。 Logback等级 ALL < TRACE < DEBUG < INFO < WARN < ERROR <FATAL <OFF 配置文件结构 configuration appender…

微信小程序读取本地json

首先在项目录下新建【server】文件夹&#xff0c;新建data.js文件&#xff0c;并定义好json数据格式。如下&#xff1a; pages/index/index.ts导入data.js并请求json pages/index/index.wxml页面展示数据

365. 水壶问题

365. 水壶问题 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 365. 水壶问题 https://leetcode.cn/problems/water-and-jug-problem/description/ 完成情况&#xff1a; 解题思路&#xff1a; /**在任意一个时刻…

[Web_Unagi]xxe注入过滤绕过

文章目录 [Web_Unagi]xxe注入过滤绕过 [Web_Unagi]xxe注入过滤绕过 提示我们需要上传文件&#xff0c;并且flag在根目录下&#xff0c; 上传文件的格式为&#xff1a; <users><user><username>alice</username><password>passwd1</password…

封装上传文件组件(axios,进度条onUploadProgress,取消请求)

目录 定时模拟进度条 方法 A.axios B.xhr 取消请求​​​​​​​ 完整代码 A.自定义上传组件 B.二次封装组件 情况 增加cancelToken不生效&#xff0c;刷新页面 进度条太快->设置浏览器网速 定时模拟进度条 startUpload() {if (!this.file) return;const totalS…

【C++】bind包装器

bind包装器 调用bind的一般形式&#xff1a;auto newCallable bind(callable,arg_list); 其中&#xff0c;newCallable本身是一个可调用对象&#xff0c;arg_list是一个逗号分隔的参数列表&#xff0c;对应给定的 callable的参数。 当我们调用newCallable时&#xff0c;newCa…

【内网穿透】配置公网访问,实现远程连接到内网群晖NAS 6.X

公网远程访问内网群晖NAS 6.X【内网穿透】 文章目录 公网远程访问内网群晖NAS 6.X【内网穿透】前言1. 群晖NAS远程操作2. 创建一条“群晖SSH”隧道 &#x1f340;小结&#x1f340; &#x1f389;博客主页&#xff1a;小智_x0___0x_ &#x1f389;欢迎关注&#xff1a;&#x1…

虚拟ip地址软件哪个好 手机虚拟ip地址软件有哪些

虚拟ip地址修改器 IP转换器软件是一种用于把不同格式的IP地址转换为另一种格式的工具。下面是几种常见的深度IP转换器软件&#xff1a; 1. 深度IP转换器 深度IP转换器是一种收费的、简单易用的在线工具&#xff0c;可以将IPv4地址转换为16进制、2进制和10进制等格式。此外&am…

面向万物智联的应用框架的思考与探索

本文转载自 OpenHarmony TSC 官方微信公众号《峰会回顾第3期 | 面向万物智联的应用框架的思考与探索》 演讲嘉宾 | 余枝强 回顾整理 | 廖 涛 排版校对 | 李萍萍 嘉宾简介 余枝强&#xff0c;OpenHarmony技术指导委员会跨平台应用开发框架TSG负责人&#xff0c;华为终端软件部…

现代C++中的从头开始深度学习【2/8】:张量编程

一、说明 初学者文本&#xff1a;此文本需要入门级编程背景和对机器学习的基本了解。张量是在深度学习算法中表示数据的主要方式。它们广泛用于在算法执行期间实现输入、输出、参数和内部状态。 在这个故事中&#xff0c;我们将学习如何使用特征张量 API 来开发我们的C算法。具…

冠达管理:A股三大指数震荡整理 机构看好反弹趋势延续

周一&#xff0c;沪深两市呈弱势震动格式&#xff0c;创业板指领跌。到收盘&#xff0c;上证综指跌0.59%&#xff0c;报3268.83点&#xff1b;深证成指跌0.83%&#xff0c;报11145.03点&#xff1b;创业板指跌1%&#xff0c;报2240.77点。 资金面上&#xff0c;沪深两市昨日合计…

基于随机森林的回归分析,随机森林工具箱,随机森林的详细原理

目录 背影 摘要 随机森林的基本定义 随机森林实现的步骤 基于随机森林的回归分析 随机森林回归分析完整代码及工具箱下载链接&#xff1a; 随机森林分类工具箱&#xff0c;分类随机森林&#xff0c;随机森林回归工具箱&#xff0c;回归随机森林资源-CSDN文库 https://download.…

C++11之右值引用

C11之右值引用 传统的C语法中就有引用的语法&#xff0c;而C11中新增了的 右值引用&#xff08;rvalue reference&#xff09;语法特性&#xff0c;所以从现在开始我们之前学习的引用就叫做左值引用&#xff08;lvalue reference&#xff09;。无论左值引用还是右值引用&#…