当前位置: 首页 > news >正文

C++初阶篇----新手进村

目录

  • 一、什么是C++
  • 二、C++关键字
  • 三、命名空间
    • 3.1命名空间的定义
    • 3.2命名空间的使用
  • 四、C++输入和输出
  • 五、缺省参数
    • 5.1缺省参数的概念
    • 5.2缺省参数的分类
  • 六、函数重载
    • 6.1函数重载的概念
    • 6.2函数重载的原理----名字修饰
  • 七、引用
    • 7.1引用概念
    • 7.2引用特性
    • 7.3常引用
    • 7.4引用的使用
    • 7.5传值、传引用效率比较
    • 7.6引用和指针的区别
    • 7.7引用与指针的不同点
  • 八、内联函数
    • 8.1内联函数概念
    • 8.2 特性
  • 九、auto关键字
    • 9.1类型别名思考
    • 9.2 auto简介
    • 9.3 auto的使用细则
    • 9.4 auto不能推导的场景
  • 十、C++范围的for循环(C++11)
    • 10.1范围for的语法
    • 10.2范围for的使用条件
  • 十一、nullptr指针空值(C++11)

一、什么是C++

二、C++关键字

相较于C语言,C语言有32个关键字,而C++则有63个关键字

在这里插入图片描述

三、命名空间

在C/C++中,变量、函数等的类都是大量存在的,这些变量、函数和类的名称将都存
在于全局作用域中,可能会导致很多冲突。
使用命名空间的目的是对标识符的名称进行本地化,
以避免命名冲突或名字污染,**namespace**关键字的出现就是针对这种问题的

3.1命名空间的定义

命名空间的普通定义

//命名空间的普通定义
namespace bit
{int rand = 10;int scanf = 2;int Add(int x, int y){return x + y;}
}

命名空间的嵌套定义

//命名空间的嵌套定义、
namespace bit1
{int rand = 10;int scanf = 2;int Add(int x, int y){return x + y;}namespace bit2{int c;int d;int Sub(int left, int right){return left + right;}}
}

同一个命名空间的合并
同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中

3.2命名空间的使用

作用域:

符号**“::”**在C++中叫做作用域限定符,我们通过“命名空间名称::命名空间成员”便可以访问到命名空间中相应的成员

加命名空间名称及作用域限定符,嵌套调用可以用"xxx::bbb::"

	std::cin >> i;cout << "xxxx" << endl;cout << bit::rand << endl;

使用using将命名空间中某个成员引入

using std::cout;
using std::endl;

使用using namespace 命名空间名称 引入

using namespace bit;
int main()
{int i = 0;std::cin >> i;cout << "xxxx" << endl;cout << bit::rand << endl;Add();
}

四、C++输入和输出

std是C++标准库的命名空间名,C++将标准库的定义实现都放在这个命名空间中

使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
以及按命名空间使用方法使用std。

输出流:cout和endl,其中endl表示换行输出.他们都包含在的头文件中 输入流:cin
<<是流插入运算符,>>是流提取运算符

在C++的输入输出可以自动识别变量类型
在这里插入图片描述

五、缺省参数

5.1缺省参数的概念

缺省参数是声明或定义函数时为函数的一个参数指定一个缺省值,在调用函数的时候,如果没有传参(也就是没有指定的实参)则采用该形参的缺省值
在这里插入图片描述

5.2缺省参数的分类

全缺省参数

void myq(int x=5,int y=2,int z=5)
{cout << "x=" << x << endl;cout << "y=" << y << endl;cout << "z=" << z << endl;}

半缺省参数

void fun(int x, int y = 10)
{cout << x << y << endl;
}
  1. 半缺省参数必须从右往左依次来给出,不能间隔着给
  2. 缺省参数不能在函数声明和定义中同时出现

六、函数重载

同一个函数名可以定义为多个不同类型的函数

6.1函数重载的概念

函数重载是指在同一个作用域内,可以定义多个具有相同名称但参数列表不同的函数。C++通过函数的参数个数、类型或顺序的不同来实现函数重载。

通过使用相同的函数名来实现不同的功能和操作

//1.参数类型不同
int max(int x, int y)
{if (x > y)return x;elsereturn y;
}double max(double x, double y)
{if (x - y > 0)return x;else return y;
}
//2.参数个数不同
void max()
{cout << "max()" << endl;
}//3.参数类型的顺序
void min(int x, char y)
{cout << x << y << endl;
}void min(char x, int y)
{cout << x << y << endl;
}int main()
{max(1, 4);max(1.2, 4.2);max();min(6, 'm');min('m', 5);return 0;
}

在这里插入图片描述

6.2函数重载的原理----名字修饰

C/C++中,一个程序在运行中都需要经历这四个阶段:预处理、编译、汇编、链接
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  1. 编译后链接前,a.o的目标 文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。那么 怎么办呢?
  2. 链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就会到b.o的符号表中找Add的地址,然后链接到一起。
  3. 在c中的链接,函数是通过函数名来寻找函数的地址
  4. 而C++中的链接,会通过函数名和函数参数的类型来寻找

七、引用

7.1引用概念

引用不是新定义一个变量,而是给已有的变量去一个别名,本质上就是同一个变量的不同叫法。
因此编译器不会为引用变量开辟内存空间,他和它引用的变量共用同一块内存空间

类型& 引用变量名(对象名) = 引用实体;
在这里插入图片描述

注意:引用类型必须和引用实体为同一种类型

7.2引用特性

  1. 引用在定义是必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再不能引用其他实体

7.3常引用

在这里插入图片描述

int main()
{const int a = 10;const int& ma = a;//int& fa = a;        //编译出错double b = 3.14;double & fa = b;const int& c = 10;double d = 12.34;//int& rd = d; // 该语句编译时会出错,类型不同const int& rd = d;cout << b << endl << c << endl;return 0;	
}

7.4引用的使用

参数引用

void Swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}

返回值引用

int& count()
{static int x = 0;x++;return x;
}

引用函数返回值的作用
避免不必要的对象拷贝开销,提高程序的性能;支持连续赋值和链式调用,使代码更加简洁和易读;同时允许函数返回修改后的对象,增加了程序的灵活性。因此,在设计函数接口时,如果函数返回的是一个非基本数据类型的对象,考虑返回值引用通常是一个不错的选择。

7.5传值、传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{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;
}

在这里插入图片描述
传值和指针在作为传参以及返回值类型上效率相差很大

7.6引用和指针的区别

语法的概念上,引用就是一个别名,没有独立空间,同引用实体共用一块空间
而在编译器实现的底层上,实际是有空间的,因为引用也是按照指针方式来实现的,只是较于c来说,把事情的重复性交给了底层,来提高效率

7.7引用与指针的不同点

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

八、内联函数

8.1内联函数概念

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率
在这里插入图片描述
这里便涉及到汇编的一些知识

内联函数实质是,将整个函数(也就是这一堆的指令) ,直接展开使用
比较 宏: 宏虽然也能直接展开函,但宏的本质是将所写的指令从一个名字中替换

8.2 特性

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

相较于的优缺点:
优:

  1. 可以增强代码复用性
  2. 提高性能
    缺:
  3. 不方便调试
  4. 可读性差
  5. 没有类型的检查

C++有哪些技术替代宏?

  1. 常量定义 换用const enum
  2. 短小函数定义 换用内联函数

九、auto关键字

9.1类型别名思考

当程序过于复杂,类型过于繁多复杂,如

  1. 类型难以拼写
  2. 含义不明确
#include <string>
#include <map>
int main()
{std::map<std::string, std::string> m{ { "apple", "苹果" }, { "orange", 
"橙子" }, {"pear","梨"} };std::map<std::string, std::string>::iterator it = m.begin();while (it != m.end()){//....}return 0;
}

std::map<std::string, std::string>::iterator 是一个类型,但是该类型太长了,特别容易写错。

使用typedef给类型取别名确实可以简化代码,但是typedef有会遇到新的难题:

typedef char* pstring;
int main()
{const pstring p1;    // 编译成功还是失败?const pstring* p2;   // 编译成功还是失败?return 0;
}

在编程时,常常需要把表达式的值赋值给变量,这就要求在声明变量的时候清楚地知道表达式的
类型。然而有时候要做到这点并非那么容易,因此C++11给auto赋予了新的含义。

9.2 auto简介

使用auto修饰的变量,是具有自动存储器的局部变量
但实际应用中并不多见,这是为什么?

:auto不再是一个存储类型指示符,而是作为一
个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得

注意
使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

9.3 auto的使用细则

  1. auto与指针和引用结合起来使用
    用auto声明指针类型时,用auto和auto* 没有区别,但用auto声明引用类型则必须加 &
  2. 在同一行定义多个变量 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译 器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

9.4 auto不能推导的场景

  1. auto不能作为函数的参数
// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}
  1. 不能直接用来声明数组

十、C++范围的for循环(C++11)

10.1范围for的语法

C++是兼容C的,所以for循环中,C的语法依然是适用的

int main()
{for(int i=0;i<10;i++){printf("%d ",i);}return 0;
}

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因
此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范
围内用于迭代的变量
,第二部分则表示被迭代的范围

for(迭代变量 : 别迭代范围){}

int main()
{int array1[] = { 1,2,3,4,5,6 };int array2[] = { 1,2,3,4,5,6 };//仅仅只是变量的拷贝,不做修改for (int i : array1){i *= 2;}for (auto e : array1){cout << e << " ";}cout << endl;//for范围配合引用,可以做到指针的效果for (auto& i : array2){i *= 2;}for (auto i : array2){cout << i << " ";}return 0;
}

在这里插入图片描述

10.2范围for的使用条件

for循环迭代的范围必须是确定的
对于数组而言**,就是数组中第一个元素和最后一个元素的范围**;对于类而言,应该提供begin和end的办法,begin和end就是for循环迭代的范围

十一、nullptr指针空值(C++11)

声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们基本都是按照如下方式对其进行初始化:

	int* N = NULL;int* M = 0;

在C的头文件中,(stddef.h)
NULL实际是一个宏 ,所以在应用中,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦

void fun(int)
{cout << "fun(int)" << endl;
}
void fun(int*)
{cout << "fun(int*)" << endl;
}int main()
{fun(0);fun(NULL);fun((int*)NULL);return 0;
}

在这里插入图片描述
本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的
初衷相悖.
字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。

注意:

  1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入 的。
  2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
  3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr

相关文章:

  • 统计数字出现次数的数位动态规划解法-数位统计DP
  • 排序算法---快速排序
  • 深度解析与推荐:主流Web前端开发框架
  • (52)只出现一次的数字III
  • 基于鲲鹏服务器的LNMP配置
  • 人类的协同不同于机器的协同
  • 旅游|基于Springboot的旅游管理系统设计与实现(源码+数据库+文档)
  • 前端图片转base64 方法
  • Aethir和Well-Link Tech携手革新云游戏,释放人工智能(AI)潜力
  • [当人工智能遇上安全] 11.威胁情报实体识别 (2)基于BiGRU-CRF的中文实体识别万字详解
  • 部署一个在线OCR工具
  • Redis(三)主从架构、Redis哨兵架构、Redis集群方案对比、Redis高可用集群搭建、Redis高可用集群之水平扩展
  • 【Web】基于Mybatis的SQL注入漏洞利用点学习笔记
  • Terraform实战(三)-在AWS上尝试Terraform的Vault Provider
  • MySQL用心总结
  • 2017 前端面试准备 - 收藏集 - 掘金
  • avalon2.2的VM生成过程
  • golang中接口赋值与方法集
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • Nacos系列:Nacos的Java SDK使用
  • Spring核心 Bean的高级装配
  • SQLServer之索引简介
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 汉诺塔算法
  • 基于axios的vue插件,让http请求更简单
  • 警报:线上事故之CountDownLatch的威力
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 前端相关框架总和
  • 数据仓库的几种建模方法
  • 小李飞刀:SQL题目刷起来!
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • Python 之网络式编程
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • !!Dom4j 学习笔记
  • $forceUpdate()函数
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (七)c52学习之旅-中断
  • (一)kafka实战——kafka源码编译启动
  • (原)本想说脏话,奈何已放下
  • (转)德国人的记事本
  • (转载)Google Chrome调试JS
  • (转载)利用webkit抓取动态网页和链接
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .gitignore文件---让git自动忽略指定文件
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复