1.C++的版本更新

时间 阶段 内容
1998 年 C++98 C++ 官方第一个版本,绝大多数编译器都支持,得到了国际标准化组织 (ISO) 和协会认可,以模板方式重写 C++ 标准库,引入了 STL (标准模板库)
2003 年 C++03 这是 C++ 标准的一个重大修订,主要聚焦于语言的稳定性和兼容性。C++03 修订 + 98 标准中的错误和漏洞,同时引入了一些新的特性和功能,如 tr1 库(Technical Report 1)
2011 年 C++11 这是一次革命性的更新,增加了大量的新特性和功能,使得 C++ 更像一种新语言:lambda、范围 for、右值引用和移动语义、边长模版参数、STL 的容器和核心智能指针、标准线程库等
2014 年 C++14 对 C++11 的扩展,主要是修复 C++11 中漏洞以及改进,比如:泛型的 lambda 表达式的返回值类型推导,二进制字面常量等
2017 年 C++17 C++17 进一步增强了 C++ 的功能和表达能力。这次更新引入了 if constexpr、结构化绑定、折叠表达式等语法特性,同时改进了标准库中的多个组件,如 string、filesystem 等
2020 年 C++20 C++20 是 C++ 历史上的又一个重要里程碑。这次更新引入了一系列新特性和改进:协程(Coroutines)、概念(Concepts)、模块化(Modules)等,为 C++ 的未来发展奠定了坚实的基础
2023 年 C++23 C++23 是一个小版本更新,进一步完善和改进现有特性,增加了 if consteval、flat_map、import std 导入标准库等特性
2026 年 C++26 制定中

2.C++参考文档

Reference - C++ Reference

非常好用,我平时就在用这个。

3.C++在工作领域的应用

服务器端,游戏引擎,机器学习引擎,音视频处理,嵌入式软件,电信设备,金融应用,操作系统,编译器,基础架构,等等,应用范围很广。

4.C++第一个程序

#include<stdio.h>
int main()
{
    printf("hello world\n"); 
    return 0;
}

C++兼容C语言大部分语法,所以可以看到C语言的hello world依旧可以运行,不过C++的后缀文件名要改为.cpp,vs编译器就会调用C++编译器,linux下就要调用g++,不能再用gcc。

严格来说,c++版本的hello world应该这样写。

#include <iostream>
using namespace std;//这个是命名空间
int main()
{
    cout<<"hello world"<<endl;
    return 0;
}

5.命名空间

5.1namespace的价值

在C/C++中,变量、函数、类都是大量存在的,这些名称如果都在全局作用域中,可能会导致很多冲突。使用命名空间就可以对名称进行本地化,避免命名冲突或者污染。

#include <stdio.h>
#include <stdlib.h>

int rand =10;
int main()
{
    printf("%d\n",rand);//就会报错,rand重定义
    return 0;
}

5.2namespace的定义

定义命名空间,就需要用到namespace关键字,后面跟命名空间的名字,然后一对{}。

namespace本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量,命名冲突就不存在了。

C++有函数局部域,全局域,命名空间域,类域;域影响的是编译语法查找一个变量/函数/类型出处的逻辑,所以域隔离,解决了命名冲突。局部域和全局域除了影响查找逻辑,还影响变量的生命周期,命名空间域和类域不影响变量生命周期。

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

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

C++标准库都放在一个std命名空间中。

#include <iostream>
#include <stdio.h>
using namespace std;

namespace zhangsan
{    
    
    namespace lisi//命名空间是能嵌套的
    {
        int a=0;
    }
    namespace wangwu
    {
        int a=1;
    }
}

int main()
{
    printf("%d\n",zhangsan::lisi::a);//这个打印就是lisi的a
    printf("%d\n",zhangsan::wangwu::a);//wangwu的a
    return 0;
}

5.3命名空间的使用

编译查找一个变量的声明/定义是,默认在局部或者全局查找,不会进命名空间查找。

所以在使用时要指定命名空间访问,推荐使用这种方式。

或者using展开命名空间中某个成员,如果经常访问不存在冲突的成员可以这样。

展开命名空间的全部成员,不推荐冲突风险很大,只建议日常小练习使用。

6.C++输入/输出

<iostream>是input output stream的缩写,是标准的输入、输出流库,定义标准输入输出。

std::cin是istream类的对象,面向窄字符的标准输入流。

std::cout是ostream类的对象,面向窄字符的标准输出流

std::endl是一个函数,流插入输出时,相当于插入一个换行字符并刷新缓冲区。

<<是流插入运算符,>>是流提取运算符。(在C语言中还用这两个运算符做位运算左移/右移)

使用C++输入输出更方便,可以自动识别变量类型,本质是函数重载。

7.缺省参数

缺省参数是声明或者定义函数时为函数参数指定一个缺省值。在调用函数时,没有指定实参,就调用形参的缺省值,否则使用实参,C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃缺省。

带缺省参数的函数调用,必须从左往右依次给实参。

函数声明和定义分离时,缺省参数不能再函数声明和定义中同时出现,规定必须再函数声明给缺省值

8.函数重载

C++支持同一作用域出现同名函数,但是要求同名函数的形参不同,可以是参数类型不同,或者个数不同,这样C++函数调用就表现出了多态行为。注意返回值不能作为重载条件。

//类型不同
int add(int a, int b)
{
	return a + b;
}
double add(double a, double b)
{
	return a + b;
}
//参数个数不同
void f()
{
    cout<<"f()"<<endl;
}
void f(int a)
{
    cout<<"f(int a)"<<endl;
}
//参数类型顺序不同
void f(int a,char b)
{
}
void f(char b, int a)
{
}
//这两个函数构成重载,不过调用会报错,编译器不知道调用谁
void f()
{
}
void f(int a=10)
{
}

9.引用

9.1引用的概念和定义

引用不是新定义一个变量,而是给已存在变量取别名,编译器不会为引用变量开辟新空间,而是和被引用的变量共用一个内存空间。

#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	int& b = a;
	int& c = a;
	int& d = b;
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	cout << &d << endl;//可以看到a,b,c,d的地址是一样的
	return 0;
}

9.2引用的特性

引用在定义时必须初始化。

一个变量可以有多个引用。

应用一旦引用一个实体,就不能再引用其他实体。

9.3引用的使用

引用主要是用于引用传参和引用做返回值,减少拷贝提高效率和改变引用对象时同时改变被引用对象。

9.4const引用

如果要引用一个const对象,必须用const引用,const引用可以引用普通对象,因为对象访问权限在引用过程可以缩小,但是不能放大。

C++规定临时对象具有常性,所以引用临时对象必须要常引用。临时对象就是编译器临时创建的一个未命名对象。

9.5指针和引用的关系

语法概念上指针要开空间,存放变量地址,引用不用开空间。

引用在定义时必须初始化,指针建议,但是不是必须。

引用在初始化后引用的对象不能改变,指针可以不断改变指向对象。

引用可以直接访问对象,指针需要解引用。

sizeof引用时,引用对象的大小,sizeof指针,在x86是4字节,在x64是8字节。

10.inline

用inline修饰的函数叫内联函数,编译时,编译器会在调用的地方展开内联函数,这样调用内联函数就会建立栈帧了,提高效率。

但是内联对编译器只是一个建议,编译器不一定会展开。inline只适用于短小的函数,递归,代码较多的函数,内联也会被编译器忽略。

inline的目的是代替C的宏函数。

inline不建议声明和定义分离到两个文件,会导致链接错误,因为内联展开就没有函数地址,会链接报错。

11.nullptr

NULL实际是个宏,在C头文件(stddef.h)中,可以看到

#ifndef NULL 
    #ifdef __cplusplus 
        #define NULL 0 
    #else
        #define NULL ((void *)0) 
    #endif 
#endif

C++NULL可能会被定义为字面常量0,想通过f(NULL)调用f(int* x),但是NULL被定义为了0,调用成了f(int x),f((void)*NULL)调用会报错。

所以在C++11引用nullptr,nullptr是一个关键字,可以转换为任意类型指针的类型。

在C++中尽量使用nullptr

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构