C++:从C语言过渡到C++

在这篇博客中,我将会介绍从**C语言过渡到C++**的一些基础知识。

目录

C++起源

C++的关键字

输出hello,world

​编辑

命名空间

1.什么是命名空间

2.namespace的作用

3.域作用限定符

4.命名空间的使用

IO流

缺省参数

函数重载

引用

1.引用的定义

2.引用的特性

3.引用的使用

4.const引用

5.引用和指针

内联函数inline

nullptr


C++起源

在1979年 ,本贾尼·斯特劳斯特卢普 在贝尔实验室中进行复杂的软件开发时,他感受到了C语言的局限性,于是他在此基础上设计了C++。

C++在C语言的基础上添加了面向对象编程的特性:封装、继承、多态。

随后几年,C++不断完善发展,在1998年 推出了C++98, 官方第一个较为完善的版本,引入了STL(标准模板库)。

在2011年 ,C++的一次革命性的更新,增加了大量特性和功能。

在2020年 ,C++又一次巨大更新,引入了**模板(Modules)、概念(Concepts)、协程(Coroutines)**等

在公司中,使用的比较多的都是C++98和C++11.

C++的关键字

输出hello,world

cpp 复制代码
#include<iostream>
using namespace std;

int main()
{
	cout << "hello,world!" << endl;
	return 0;
}


命名空间

1.什么是命名空间

命名空间 需要用一个关键字namespace ,后跟命名空间的名字 ,然后用**{}括起来** ,在里面可以定义变量、函数、自定义类型 ,即为命名空间的成员。


2.namespace的作用

在C/C++中,变量、函数、类 是大量存在的,这些名称在全局域中可能会重复从而引发冲突。

cpp 复制代码
#include<stdlib.h>
int rand = 15;

int main()
{
	//这里会报编译错误,"rand" : 重定义;以前的定义是"函数"	
	printf("%d\n", rand);
	return 0;
}

C++中域有函数局部域,全局域,命名空间域,类域。局部域和全局域 除了会影响编译查找逻辑 ,还会影响变量的生命周期 ,命名空间域和类域不影响变量生命周期。

namespace 会定义一个域,也就是命名空间域 ,它与全局域独立,不同的域可以存在同名变量。

我们可以将rand放于一个命名空间域,从而修正上述问题。

namespace只能定义在全局 ,当然他还可以嵌套定义。

项目工程中多文件中定义 的同名namespace会认为是⼀个同namespace,不会冲突。


3.域作用限定符

既然有不同的有不同的域,那我们可以通过域作用限定符 (::)l来访问域中的成员变量。

::默认访问全局域; 在其左侧加上域名就是访问该名字的域,如上面代码,Moss::rand就时访问的Moss域中的rand变量。


4.命名空间的使用

namespace的使用主要分为两种:

1.指定命名空间访问,实际项目中推荐这种。

2.使用关键字using将命名空间的某个成员 或者全部成员展开

C++标准库 都放在⼀个叫std(standard)的命名空间中。

cpp 复制代码
#include<iostream>
using namespace std;//展开std中的所有成员

IO流

IO流其实就是输入输出流,与之相关的头文件就是**<iostream>。**

<iostream>: Input Output Stream,标准输入输出流库,定义了标准输入输出对象。

std标准库就被包含在其中。

cout、cin、endl都属于C++标准库(std)

cout:用于屏幕输出

cin:用于键盘输入

endl:输出时,增加换行符('\n')

<<是流插入运算符 ,>>是流提取运算符。(在C语言是左移/右移运算符)。

cout和cin的输出输入 通过函数重载 实现**自动识别变量类型,**无须像C语言那样指定格式。

使用格式如下:


缺省参数

缺省参数就是在声明或者定义函数时 ,为函数的实参指定一个默认值 ,无参数调用函数 时,函数就会使用该默认值。

需要注意的几个点:

1.当函数声明和定义分离时,缺省参数只能在函数声明出现 ,函数定义不能使用缺省参数。

2.缺省参数的指定在函数的声明或者定义中,规定缺省参数 必须从右往左依次指定,不能跳跃给缺省参数。

3.对于带缺省参数的函数调用 ,从左往右依次传实参,不能跳跃传。

4.全缺省: 全部形参给缺省值。

半缺省: 部分形参给缺省值。


函数重载

函数重载:同一作用域 中出现同名函数 ,但是这些函数的形参各不相同。

函数重载允许返回值的类型相等 ,但是返回值的类型不同 不能作为函数重载的标识。

1.参数类型不同

2.参数个数不同

3参数类型顺序不同

接下来我们看一个需要警惕的坑:

上面这两个函数构成函数重载 ,因为参数个数不同,但是这两个函数存在调用歧义,调用F()函数时,编译器不知道调用哪个函数。


引用

1.引用的定义

引用:给一个存在变量取别名 ,引用变量 与原变量共用一块内存空间。

语法形式:类型& 引用的别名 = 引用对象

这里a、b、c、d都是共用一块内存空间的

2.引用的特性

1. 引用的变量 必须初始化。

2. 一个变量 可以多个引用。

3. 引用一旦引用了一个变量,就不得再引用其他变量。(引用的指向不允许更改)

cpp 复制代码
int a = 5;

//编译错: ra必须初始化引用
//int& ra;

int& b = a;

int c = 10;
//这里是赋值,将c的值赋给b(a),不是改变引用的指向
b = c;

3.引用的使用

1.引用传参

2.做返回值

引用传参:

引用传参 表面上是传值,但实际上传的是地址 ,只不过是编译器帮做了。

cpp 复制代码
void Swap(int& x, int& y)//引用传参 可以替换 传址调用
{
	int tmp = x;
	x = y;
	y = tmp;
}

4.const引用

当引用一个const对象 时,必须const引用 ,否则就会权限放大,权限不允许放大,但可以缩小。

cpp 复制代码
const int a = 10;
//权限不能放大,必须用const引用
//int& ra = a;
const int& ra = a;

int b = 5;
//权限缩小是可以的
const int& rb = b;

临时对象:编译器在一块空间暂存表达式的结果时临时创建的未命名的对象。

临时对象的引用:临时对象具有常性,也必须用const引用。(不用const引用就会触发权限放大,然后就报错)

cpp 复制代码
int a = 4;
const int& ra = a * 3;//a * 3的结果存放在临时变量中,得用const引用

double d = 3.14;
const int& rd = d;//类型转换产生的中间值也存放在临时变量中,也得用const引用

5.引用和指针

1.引用必须初始化,不开空间;指针存储变量地址,语法上可以不初始化(nullptr),但是要开空间

2.引用的指向不能改变 ,而指针可以随意更改。

3.引用直接访问对象,指针要解引用。

4.sizeof的结果不同,引用结果为类型大小,但指针只跟多少位系统有关(32位4个字节,64位8个字节)

5.使用引用相对安全,指针容易出现空指针和野指针的问题。


内联函数inline

定义: 用inline修饰的函数就是内联函数

作用:内联函数在调用的时候,编译器会在调用的地方展开内联函数,这样就不需要建立函数栈帧 ,以便提高效率。

所以我们通过作用就很容易想到,内联函数设计出来是为了代替C语言的宏函数,而替代的原因是宏函数的实现很容易出错。

cpp 复制代码
//正确的宏实现
#define ADD(x, y) ((x) + (y))
// 为什么不能加分号?
// 为什么要加外面的括号?
// 为什么要加里面的括号?
//保证优先级
int main()
{
	cout << ADD(1, 2) * 5 << endl;

	int x = 1, y = 2;
	ADD(x & y, x | y);// ->(x&y + x|y)
	//+的优先级比& | 高,所以里面也要加括号

	return 0;
}

需要注意的点:

1.inline对于编译器只是建议,并不是说加了一定会在调用的地方被展开,一般来说,**inline适用于简短而又被频繁调用的函数,**对于代码较多的函数,加了inline也会被编译器忽略。

2.inline不推荐函数声明和定义分离到两个文件,如果inline函数被展开,链接时就会报错。

vs编译器在debug版本下默认不展开inline,以便调试。


nullptr

在C语言中,空指针NULL实际上是一个宏

NULL的使用不可避免存在一定的问题,本想调用指针版本的F(int* ptr),但是NULL被定义成0,从而调用了F(int x)版本,这有违初衷。

因此在C++中新增关键字nullptr,它可以转换任意类型的指针类型。

nullptr只能被隐式转换为指针类型,不能转换为整数类型,所以nullptr定义空指针可以避免类型转换。


拜拜,下期再见😏

摸鱼ing😴✨🎞

相关推荐
weixin_5310946914 分钟前
heap_4内存管理
java·开发语言·算法
余额瞒着我当琳17 分钟前
红黑树的实现--红黑树的概念、规则、效率、结构、旋转、查找、验证
数据结构·c++·算法
疯狂的维修20 分钟前
关于用C#写电机起保停控制
开发语言·c#
青少儿编程课堂23 分钟前
AC自动机多模式串匹配精讲:校园关键词巡检实战解析
c++·python·算法·bfs·信息学竞赛
longlongzihan1 小时前
LeetCode 5. 最长回文子串:从暴力匹配到中心扩展的思维演进
c++·算法·leetcode
多弗朗皮卡丘1 小时前
C++继承
c++·继承
geovindu1 小时前
rust: Abstract Factory pattern
开发语言·后端·设计模式·rust·抽象工厂模式
“AI国潮设计-小江”1 小时前
《Python+SDXL实战:用ControlNet批量生成“英歌舞麻将糕”IP,附自动化脚本与商用思路》
开发语言·人工智能·python·prompt·aigc
Cc.Y2 小时前
Java零基础入门:封装与继承 —— 从“裸奔“到“穿衣服“,从“重复造轮子“到“站在巨人肩膀上“
java·开发语言
Escalating_xu2 小时前
【C 语言】深入理解指针(4):回调函数、qsort、void * 与泛型排序的模拟实现
java·c语言·开发语言