C++——基础概念

C++——基础概念
C++是兼容C的,所以我们可以在C++环境下写C语言。

C++之父:本贾尼・斯特劳斯特卢普。

一、命名空间

#include<stdio.h> #include<stdlib.h> int main() { int rand = 10; printf("%d\n", rand);//代码可以正确执行 } 
#include<stdio.h> #include<stdlib.h> int rand = 10; int main() { printf("%d\n", rand);//会编译报错 }

思考:stdlib.h中存在rand这个函数,那么我们确自定义了rand这个变量。当random是局部变量时,代码可以成功执行,当random是全局变量时,代码确会引起编译报错,这是什么原因呢?

下面我们需要了解C++的标识符查找规则和引起标识符命名冲突的本质原因。

(1)C++标识符查找规则

标识符:变量、函数、类、常量、命名空间。

编译器查找标识符时,会从当前最内层的作用域开始查找;如果找到了,就不会再去外层作用域查找。

(2)引起标识符命名冲突的本质原因

同一作用域下不能存在同名的标识符。

那么用怎么样才能避免编译报错呢?

这里就引入了命名空间的概念。

(3)命名空间

①概念

命名空间就是我自己造了一个域,用来存放标识符。用来解决同一个域下命名冲突的问题。

用(命名空间名::标识符)来访问我域里的标识符。

②语法

语法:

namespace 命名空间名 { // 你自定义的标识符 }

③解决标识符冲突问题

#include<stdio.h> #include<stdlib.h> namespace mycode{ int rand = 10; } int main() { printf("%d\n", mycode::rand);//正常打印出10 }

那么在同一个命名空间下,标识符一样该怎么处理,这里我们就需要了解命名空间的嵌套。

(4)命名空间的嵌套

①概念

在父域里辟多个子域。用来解决父域中标识符冲突问题。用(父域命名空间名::子域1::标识符)来访问我域里的标识符。

②语法

namespace 外层命名空间名 { namespace 内层命名空间名1 { // 你自定义的标识符 } namespace 内层命名空间名2 { // 你自定义的标识符 } //...... }

③示例

#include<stdio.h> namespace code{ namespace codeA { int a = 10; } namespace codeB { int a = 20; } } int main() { printf("%d\n", code::codeA::a);//打印10 printf("%d\n", code::codeB::a);//打印20 }

(5)命名空间的使用

①指定命名空间访问

就是我们前面用的::

②展开某个成员访问

就是访问命名空间里的某个成员。

语法:

using 命名空间名::成员;

示例:

#include<stdio.h> namespace name { int a = 3; int b = 6; } int main() { using name::a;//展开某个成员 printf("%d\n", a); }

③展开命名空间的全部成员

语法:

using namespace 命名空间名; 

示例:

#include<stdio.h> namespace name { int a = 3; int b = 6; } int main() { using namespace name;//展开全部成员 printf("%d\n", a); printf("%d\n", b); }

(6)补充

在多个文件使用命名空间时

C++ 不允许同一个作用域下有两个同名的类或变量,但允许同一个命名空间被写在不同的文件、不同的位置,编译器会自动把它们合并成一个。

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

二、C++的输入输出

(1)<iostream>

是Input Output Stream的缩写,为你提供了输出输出(cin、cout)和操作规则(<<、>>)。

(2)std::cin和std::cout

std::cin是在控制台输入的意思,我们知道C++的标准库都放在std这个命名空间里。所以前面要加上std::,这里面的c是console(控制台)的意思,in是input(输入的意思)。
std::cout与上面唯一的区别是out是输出的意思。所以表示的是在控制台输出的意思。

(3)<< 和 >>

<<是流插入运算符,和cout搭配使用。例如std::cout<<"hello world"。把hello world在终端打印出来。可以一次打印多个内容。
#include<iostream> int main() { using namespace std; cout << "hello world" << endl; cout << "我的刀盾喜欢奶龙" << endl << "咕咕嘎嘎" << endl;//在屏幕上打印两行内容 }
>>是流提取运算符,和cin搭配使用。也可以一次输入多个内容。
#include<iostream> int main() { using namespace std; int a,b; cout << "请输入两个整数:"; cin >> a >> b; cout << "两个数之和为:" << a + b << endl; }

需要注意的C++可以自动识别变量类型,不需要我们手动输入占位符。

(4)endl

endl表示换行的意思。

三、缺省参数

(1)基本概念

定义函数时,给定参数一个默认值(这个值也叫做缺省值)。在传参数时,如果不传参数就使用默认值,传参数就使用你传的参数。
#include<iostream> using namespace std; void Print(int a= 3) { cout << a << endl; } int main() { Print();//打印3 Print(6);//打印6 }

(2)全缺省

给函数的全部参数设置缺省值。

#include<iostream> using namespace std; void Print(int a= 3,int b = 2) { cout << a << "," << b << endl; } int main() { Print();//打印3,2 Print(0,0);//打印0,0 }

(3)半确省

给函数的部分参数设置缺省值。半缺省中,C++规定缺省值必须从右向左连续传。在使用时,必须传够没用缺省值的参数,且是按照从左向右传的顺序。
#include<iostream> using namespace std; void Print(int a, int b = 1, int c = 2) { cout << a << "," << b << ","<< c << endl; } int main() { //Print();//没有传够参数,会触发编译错误 Print(0);//打印0,1,2半缺省起码传一个 Print(6,6);//打印6,6,2 Print(5,5,5);//打印5,5,5 }

函数声明和定义分离时,函数的缺省参数只能出现一次,且出现在声明部分。

#include<iostream> using namespace std; void Print(int a, int b = 3);//函数声明部分(缺省值必须写在声明里) void Print(int a , int b) {//函数定义部分 cout << a << "," << b << endl; } int main() { Print(3);//打印3,3 Print(2,6);//打印2,6 }

四、函数重载

C++规定在同一作用域内,可以存在一个或多个同名函数。但是这个同名函数需要满足参数个数不同 || 参数类型不同  || 参数顺序不同(参数类型的顺序不同)。

#include<iostream> using namespace std; int Add(int a, int b, int c) {//参数个数不同 return a + b + c; } int Add(int a, int b) { return a + b; } int main() { int a = Add(1,1,1); int b = Add(1, 1); cout << a << endl << b << endl; }
#include<iostream> using namespace std; int Add(int x,int y) {//参数类型不同 return x + y; } double Add(double x, double y) { return x + y; } int main() { int a = Add(2, 3); double b = Add(1.2, 1.3); cout << a << endl << b << endl; }
#include<iostream> using namespace std;//参数类型不同 double Calc(int a,double b) { return a + b; } double Calc(double a,int b) { return a - b; } int main() { double a = Calc(2, 2.2); double b = Calc(2.2, 2); cout << a << endl;//a的参数第一个是整型,第二个是浮点型,所以调的是加法函数(4.2) cout << b << endl;//b的参数第一个是浮点型,第二个是整型,所以调的是加法函数(0.2) }

五、引用(reference)

(1)基本概念

给已有的变量起一个别名。直接在原内存上操作这个变量。

(2)语法

类型& 引用别名 = 引用对象;

以我们以前常写的Swap函数为例,我们来体会引用的妙处。

#include<iostream> using namespace std; void Swap(int* a, int* b) {//用指针的写法 int tmp = *a; *a = *b; *b = tmp; } int main() { int a = 2, b = 3; cout << "交换前" << "a = " << a << " " << "b = " << b << endl; Swap(&a, &b); cout <<"交换后" << "a = " << a << " " << "b = " << b << endl; }
#include<iostream> using namespace std; void Swap(int& a, int& b) {//用引用的写法 int tmp = a; a = b; b = tmp; } int main() { int a = 2, b = 3; cout << "交换前" << "a = " << a << " " << "b = " << b << endl; Swap(a, b); cout << "交换后" << "a = " << a << " " << "b = " << b << endl; }

(3)引用的要求

①初始化

对于局部/全局使用引用时必须进行初始化。比如顺序表的初始化,在main函数内部使用引用。
#include<iostream> using namespace std; int main() { int a = 10; int& b = a;//引用时必须进行初始化 cout << &a << endl; cout << &b << endl;//在这里可以看到a,b是同一个地址 }
对于函数形参里的引用,你传的实参就是已经完成了初始化。比如前面的Swap函数。你传完参数,其实就完成了对形参的初始化。

②命名

对于不同作用域下引用的别名可以相同,比如我们上面的Swap函数。同一作用域下引用的别名不能与原变量的名字相同。

③多个引用

一个变量可以有多个引用,一个引用的改变一定会改变原变量和其它引用的值。

#include<iostream> using namespace std; int main() { int a = 2; int& b = a; int& c = a;//这里可以写a也可以写b cout << "变化前" << a << ","<<b << ","<< c << endl; c++; cout << "变化后" << a << "," << b << "," << c << endl;//这里可以观察到 //a,b,c的值均发生了变化 }

④引用的绑定问题

引用一旦绑定某个实体(有内存地址,能存储数据的对象;例如变量、数组),就终身只是这个实体的别名。再次对引用的操作,只是在修改引用的值,内存永远都是那一块。
int main() { int a = 2; int b = 3; int& ra = a; ra = b;//只是赋值操作 //int& ra = b;//重定义错误 }

⑤引用的优点

引用在实践中往往用于函数传参或者做返回值。因为它直接对内存进行操作,就减少了拷贝从而提高了时间效率。

六、const引用

(1)概念

被const修饰的引用。原数据进行const引用后权限只能不变或者变小。

(2)权限变化

原变量权限为只读,const引用后权限还是只读。
int main() { const int a = 3;//权限为只读,不能修改 a = 3的值 const int& ra = a;//权限仍然为只读,不能修改 ra = 3的值 //int& ra = a;//错误写法,权限不能被放大 }
原变量为可读可写,const引用后权限为只读。
int main() { int a = 3;//可读可写 const int& ra = a;//只读 a = 6;//正确写法,没有超出权限 //ra = 3;//错误写法,超出了权限 }

(3)const引用修饰临时变量

①什么是临时变量

变量是指内存空间和存储的值。
临时变量是指为了保证代码能跑,编译器自己制定的一份临时空间。生命周期随着这条语句的执行结束立马销毁。

常见的有单独的常量(表达式算出来没有用变量存储的也算),不同类型转化时触发的临时变量的创建。

②const引用可以修饰临时变量的原因

对于普通的引用只能绑定有内存地址的变量。核心原因是普通的引用可读可写,对于临时变量这种悄么的产物,本身就不安全。你还权限放大,这不就太过分了。
而const引用可以修饰临时变量的主要原因就是你临时变量虽然本身就不安全。反正我只读,都会把你改为安全的,反正不会对你进行操作。唯一的变化就是延长了临时变量的生命周期,const引用什么时候销毁,临时变量什么时候销毁。

③const引用修饰常量

int main() { const int& ra = 20;//安全 int& rra = 20;//不安全,属于权限放大 }
int main() { int a = 20; const int& ra = a * 3;//安全 int& rra = a * 3;//不安全,权限放大 }

④const引用修饰不同类型转化

int main() { int a = 3; const double& ra = a;//安全 double& rra = a;//不安全,权限放大 }

(4)引用和指针的区别

①语法:引用只是给变量取一个别名,不需要单独再开空间。而指针是存储地址的变量,所以需要单独开空间。
②初始化:引用在定义时必须进行初始化;而指针一般建议初始化,避免野指针。
③特性:引用在绑定一个对象后,就不能再改变;而指针绑定一个对象后可以换帮绑。
④访问:引用可以直接访问对象;而指针需要解引用才能访问对象。
⑤大小:引用的大小取决于对象的大小;指针的大小取决于操作系统的位数(32位下占4个字节;64位下占八个字节)
⑥安全性:指针很容易出现空指针和野指针;而引用不存在这个问题。

七、宏

(1)概念

 宏是在预处理阶段,给一段文本(值/表达式/代码)绑定一个宏名(符号),分为有参宏和无参宏。

(2)无参宏

语法:

#define 宏名 替换文本

例子:

#define val 18 int main() { using namespace std; cout << val << endl;//在执行程序是编译器会自动将val换成18 }

(3)有参宏

语法:

#define 宏名 (参数1,参数2,……) 替换文本//括号里是参数列表

例子:

#define Add(a,b) ((a) + (b)) int main() { using namespace std; cout << Add(2, 3) << endl;//输出5 }

注意:这里a和b加括号,原因是为了避免运算符优先级带来的计算错误。

八、inline

(1)概念

被inline修饰的函数叫做内联函数。inline的作用是将代码在调用处展开,不需要再建议栈帧了,提高了效率。

(2)注意

inline只是建议,编译器可以采纳也可以不采纳。一般内联函数都是几行的小代码。
#include<iostream> using namespace std; inline int Add(int a,int b) { return a + b; } int main() { cout << Add(2, 3) << endl;//就是这个意思cout << 2+3 << endl; } 

(3)内联函数和宏的区别

①本质:内联函数是函数;宏是文本替换
②运算符优先级:内联函数不存在问题;宏需要手动添加括号
③调试:内联函数可以调试,宏不能调试
④编译器:编译器可以拒绝内联;编译器不能拒绝宏,宏是强制替换

八、nullptr

(1)概念

nullptr是C++11引入的一个关键字,用来表示空指针。

(2)引入的原因

NULL在C++表示的是0的意思,如果在函数重载时,就会发生到底读取错误。
#include<iostream> using namespace std; void Print(int* x) { cout << "int*" << endl; } void Print(int x) { cout << "int" << endl; } int main() { Print(NULL);//你预期的结果是int,可是运行结果确是int Print(nullptr);//符合预期结果 }

Read more

C++短信通知接口示例代码:高性能C++发送通知短信的接口实现及调用逻辑

C++短信通知接口示例代码:高性能C++发送通知短信的接口实现及调用逻辑

在后端开发场景中,短信通知是系统触达用户的核心能力之一,而基于C++开发的高性能服务,对短信接口的调用效率、稳定性要求更高。本文将聚焦c++短信通知接口API示例代码,从底层调用逻辑拆解、实战代码实现、异常处理等维度,手把手教你实现高性能的C++短信通知接口调用,解决开发者在对接短信接口时遇到的参数配置、请求异常、性能优化等核心痛点。 一、C++短信通知接口调用核心原理拆解 1.1 短信接口调用的基本流程 C++调用短信通知接口本质是通过HTTP协议与短信服务商的服务端建立通信,完成参数传递与响应接收,核心流程可分为4步: 1. 构建符合接口规范的HTTP请求(包含请求头、核心参数); 2. 建立网络连接,发送请求到短信接口地址; 3. 接收服务端响应数据并解析; 4. 根据响应结果处理成功/失败逻辑,完成重试或日志记录。 1.2 高性能调用的关键设计要点 C++作为编译型语言,实现高性能短信接口调用需关注两个核心: * 网络请求层面:使用异步非阻塞IO(如libcurl的multi接口)避免主线程阻塞; * 数据处理层面:

By Ne0inhk
【C++:继承】C++面向对象继承全面解析:派生类构造、多继承、菱形虚拟继承与设计模式实践

【C++:继承】C++面向对象继承全面解析:派生类构造、多继承、菱形虚拟继承与设计模式实践

🔥艾莉丝努力练剑:个人主页 ❄专栏传送门:《C语言》、《数据结构与算法》、C/C++干货分享&学习过程记录、Linux操作系统编程详解、笔试/面试常见算法:从基础到进阶 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬艾莉丝的简介: 🎬艾莉丝的C++专栏简介: 目录 C++的两个参考文档 4  ~>  派生类的默认成员函数专题 4.4  实现一个不可继承类实现 4.4.1  间接实现:【C++98】构造函数私有的类不能被继承 4.4.2  直接实现:final关键字修改基类 4.4.3  代码实现 4.4.4  final关键字

By Ne0inhk

C/C++ static关键字详解(最全解析,static是什么,static如何使用,static的常考面试题)

C/C++ static 关键字最全详解(2026版) 小白到高手、笔试到面试一次讲透! 一、一句话核心总结 static 是“让变量/函数的生命周期或可见范围改变”的关键字,它有三种完全不同的含义,取决于用在什么位置**: 1. 改变存储期(让局部变量变成“全局寿命”) 2. 改变链接性(让全局变量/函数“只在本文件可见”) 3. 属于类而非对象(类静态成员) 记不住全部也没关系,记住这三句话就够日常和面试用了: * 局部 static = “函数内永生变量” * 全局 static = “本文件私有变量/函数” * 类 static = “全类共享成员” 二、static 的三种核心用法对比表(背这个表就够了) 用法位置C语言支持C++支持含义生命周期可见范围默认初始化值局部静态变量YesYes存储期变为静态(函数结束后不销毁)整个程序本函数0全局静态变量YesYes链接性变为内部链接整个程序本文件0全局静态函数YesYes链接性变为内部链接(不可被其他文件调用)整个程序本文件-类静态成员变量NoYes属于类,

By Ne0inhk

C++ 标准库中的 reverse 函数

C++ 标准库中的 reverse 函数 * 一.函数原型 * 二.函数参数 * 三.使用示例 * 1.反转数组 * 2.反转vector * 3.反转string * 4,反转部分元素 * 四.复杂度分析 * 五.注意事项 * 六.相关函数 * 1.reverse_copy * 2.自定义反转算法实现 * 3.与反向迭代器的区别 在C++标准库中,reverse函数用于反转序列。它定义在< algorithm >头文件中。以下是详细说明: 一.函数原型 template<classBidirectionalIterator>voidreverse(BidirectionalIterator first, BidirectionalIterator

By Ne0inhk