news 2026/6/15 17:40:20

从C到C++入门:C++有而C语言没有的基础知识总结

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从C到C++入门:C++有而C语言没有的基础知识总结

前言

从C语言到C++的转变无疑是巨大的:从面向过程编程到面向对象编程……如果一门心思扑到”封装、继承、多态“上学习,恐怕学到后面就会被一些语法整的困惑不解。

本文的目的就是尽量填平C语言与C++之间隐形的坑:C++常用但C语言却没有的基础知识。

本文不仅适合于用做初学C++的入门文章,还可以帮助不清楚C与C++之间差异的读者理清思绪。


一、namespace是什么?

1.情景引入

在C语言编写的代码中,存在着大量的变量、函数。而这些变量、函数又都存储于全局作用域中,这就引出了一个问题:如果变量名与函数名相同的情况下,会导致很多冲突。

如代码:

代码语言:javascript

AI代码解释

#include<iostream> using namespace std; int test(int a) { return a; } int main() { int test = 1; cout << test(test); return 0; }

(cout相当于C语言的printf,cin相当于C语言中的scanf,<<是流插入运算符,>>是流提取运算符,cout/cin不需要像printf/scanf输入输出时那样手动控制格式,C++的输入输出可以自动识别变量类型。

这段代码放在编译器上是编译错误的,原因也很显然:test重定义了。编译器不知道使用的test指的是函数还是变量,这就造成了命名冲突。

C语言没办法解决类似这样的命名冲突问题而C++通过namespace关键字,成功解决了名称冲突的问题。

2.命名空间定义

namespace用法:

命名空间需要用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{} 中即为命名空间的成员。

前面提到C语言将所有的变量、函数都放在全局作用域中,从而造成冲突。

C++允许程序员通过namespace关键字自定义命名空间(作用域),自定义的命名空间同全局作用域一样,也可以以命名空间中可以定义变量/函数/类型。

如:

代码语言:javascript

AI代码解释

namespace a1 { int hello = 6; int test(int a) { return a; } }

那么该如何使用已经定义好的命名空间呢?

3.命名空间的使用

命名空间的使用有三种方式:

①使用某变量/函数前,加空间名称与作用限定符"::".

代码语言:javascript

AI代码解释

int main() { cout << a1::hello; return 0; }

使用某变量/函数前,使用using将命名空间中某个成员引入全局作用域;

代码语言:javascript

AI代码解释

using a1::hello; int main() { cout << hello; return 0; }

③使用某变量/函数前,使用using namespace “命名空间名”将整个空间引入;

(谨慎使用,防止再次出现冲突问题)

代码语言:javascript

AI代码解释

using namespace a1; int main() { cout << hello; return 0; }

例如如上述代码通过加入namespace命名空间就能编译通过:

明确告诉编译器,我使用的是a1空间中的函数test,未加作用域限定符的就是全局作用域中的变量test。

代码语言:javascript

AI代码解释

#include<iostream> using namespace std; namespace a1 { int hello = 6; int test(int a) { return a; } } int main() { int test = 1; cout << a1::test(test); return 0; }

现在再回过头看“using namespace std”是什么意思就一目了然了。

常见教材上一般直接让初学者直接使用“using namespace std”,却又迟迟不说明原因,其实原因很简单:

<iostream>头文件中包含有cin、cout等标准输入输出的声明,但考虑到命名冲突的问题,于是C++将相关声明都放进了std命名空间中。如果不将std空间通过using展开,那么使用std空间里的成员就需要作用限定符,如std::cout。 实际上std中可以不止有<iostream>头文件中的声明,其他头文件如<vector><string>的声明也可以在其中。

这里还需要指出一个容易误解的区域:很多初学者误以为cin等“函数”的实现是在std中。其实不然:std的主要作用是避免名称冲突,防止标准库的名字(如cout)和你自己写的代码名字(比如你定义一个cout变量)打架。它们的定义是在C++标准库的预编译二进制文件中,std中的声明是为了方便后续的编译链接。

最后指出:

std命名空间的内容是随着包含的头文件动态增长的,且未包含的头文件中的声明不会进入std。

每包含一个标准库头文件(如<vector>),该文件就会向std命名空间内添加新的声明,这是 C++ 模块化设计的关键特性,也是一般教材没有细说的地方。


二、缺省参数

1.缺省参数概念

缺省参数指:

在声明或者定义函数时,为形参预备一个值,在调用该函数时,如果没有传入实参就采用该形参的缺省值,否则使用指定的实参。

这个预备值的名称叫做缺省值,有缺省值的参数叫缺省参数,有缺省参数的函数叫缺省函数。

代码语言:javascript

AI代码解释

#include<iostream> using namespace std; void fun(int a = 100) { cout << a; } int main() { fun();//没有传参时就用缺省值 fun(10);//传参了就用实际参数 return 0; }
2.缺省参数细节

缺省参数可以分为全缺省参数和半却参数。

全缺省参数就是该函数的所有参数都有缺省值;半缺省参数,指该函数的某一个参数有缺省值,但不是所有函数都有缺省值。

还有几点小细节:

①半缺省参数:若某个形参是缺省参数,那它之后的参数就必须是缺省参数;

②缺省参数不能在函数声明和定义中同时出现,防止重定义缺省值;

③缺省值必须是常量或者全局变量

C语言并不支持缺省值。


三、函数重载

1.函数重载概念

函数重载:

C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,用来处理实现功能类似数据类型不同的问题。注意:没有按返回值区分!

代码语言:javascript

AI代码解释

int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } int main() { cout << add(1, 2) << endl; cout << add(3.1, 4.2) << endl; return 0; }

编译器是怎么做到区分这两个重载函数的呢?

2.重载原理:C++的名字修饰规则

首先需要明确在不同的环境下,同一个程序中函数被编译后产生的名字是不一样的。

比如Linux与windows有关C++的名字修饰规则就截然不同,我们以较为清晰明了的Linux规则结合上述重定义代码为例做说明:

上述代码在Linux G++编译后形成的可执行文件中两个add函数的函数名如下,

我们看到两个add函数的函数名发生了改变,add(int ,int )型函数名,从add——>_Z3addii;add(double,double)型,从add——>_Z3adddd。

在Linux环境下C++名字修饰规则是:

  1. 前缀_Z表示 C++ 名称
  2. 长度+函数名5print表示函数名print有 5 个字符
  3. 参数类型编码
    • iint
    • ddouble
    • ffloat
    • cchar
    • P→ 指针(如Pi表示int*

总结:g++的函数修饰后变成【_Z+函数长度 +函数名+类型首字母】。注意:没有返回值!

而C语言编译后,其中的函数名就不会有这样的变化。

所有C++能实现函数重载,C语言不能的根本原因是:C++有着另一套函数名字修饰规则。


四、引用

“引”用在C++中经常使用,但在C语言中完全没有“引用”的身影。

1.引用的概念

引用概念

引用,并非定义一个新变量,而是为已有变量取一个别名。引用与被引用的变量指向同一块地址空间。类型& 引用变量名(对象名) = 引用实体;

代码语言:javascript

AI代码解释

int main() { int a = 1; int& A = a; //下面两次输出完全一样 cout<<a<<endl; cout<<A<<endl; }

从概念上看,既然引用与被引用变量指向同一块空间,所以对它们进行操作时是同样的效果:

"A=7"等价于"a=7",都是被指向的那块空间数据被修改为“7”。

注意:引用的类型必须与被引用的变量类型一致!

2.引用的特性

1. 引用在定义时必须初始化;2. 一个变量可以有多个引用;3. 引用一旦引用一个实体,再不能引用其他实体;4.常变量只能被常引用所引用;

1. 引用在定义时必须初始化;

如下述代码,编译器都会报错或者达不到预期效果

引用未初始化:

编译器报错:“error C2530: “A”: 必须初始化引用”

代码语言:javascript

AI代码解释

int main() { int a = 1; int& A; return 0; }

3. 引用一旦引用一个实体,再不能引用其他实体;

引用不可更改引用对象:

这里本意是想更改引用A的指向,使A从指向a转化到指向b。

但引用不能更改指向,所以下述代码实质上是将b变量的值赋值给了A(a)变量;

代码语言:javascript

AI代码解释

int main() { int a = 1, b = 2; int& A = a; A = b; return 0; }

4.常变量只能被常引用所引用;

所谓常变量,即被const修饰的变量,是不可更改的。常引用同理。

换句话说,常变量只有读权限,没有写权限,所以引用常变量的引用也必须只有读权限,而没有写权限。

代码语言:javascript

AI代码解释

int main() { const int b = 2; const int& B = b;//正确 int& A = b;//错误 return 0; }

那么普通变量能否被常引用所引用呢?

答案是肯定的,让我们分析一下:

普通变量具有可读可写的权限,而常引用仅有可读权限。如果将普通变量被常引用所引用,这是发生权限的下降,是可接受的。

所以,编译器允许引用变量对原变量的操作权限下降,而不允许权限上升。

引用变量权限<=被引用变量权限

3.引用的使用场景
1)引用传参

还记得刚接触指针时写的swap函数吗?那时形参用的是指针实现,其原理是:函数调用时将原变量的地址传入函数,通过指针直接对该地址上的数据进行操作。

同理,引用也是指向被引用变量的同一块地址,所以引用也可以实现交换函数swap:

代码语言:javascript

AI代码解释

void swap(int& left, int& right) { int temp = left; left = right; right = temp; }
2)引用做返回值

引用做返回值?如下所示

代码语言:javascript

AI代码解释

int& add(int a, int b) { int c = a + b; return c; }

原理也很简单,在函数内部有个int c的局部变量,函数用引用的形式返回c变量存储的数据。

但这里有一个十分容易引起bug的细节:

首先明确函数中的c变量是一个局部变量,当函数调用完毕后,函数所用到的所用空间都会被系统释放,以便调用其他函数。

问题在于接受函数引用返回值的变量!如果是普通变量,那还好;但如果是引用变量,则可能出现bug。

比如下代码:打印出来的是3?还是7?咋一看打印的肯定是3才对。

https://www.dongchedi.com/article/7598265380330848830
https://www.dongchedi.com/article/7598273072999186968
https://www.dongchedi.com/article/7598274901841379865
https://www.dongchedi.com/article/7598276424889336345
https://www.dongchedi.com/article/7598275637006664254
https://www.dongchedi.com/article/7598279236490723865
https://www.dongchedi.com/article/7598274890558800409
https://www.dongchedi.com/article/7598282614747251224
https://www.dongchedi.com/article/7598276969335669310
https://www.dongchedi.com/article/7598278977895121470
https://www.dongchedi.com/article/7598282709198717464
https://www.dongchedi.com/article/7598281407030936089
https://www.dongchedi.com/article/7598277471599346201
https://www.dongchedi.com/article/7598283447504896536
https://www.dongchedi.com/article/7598287089956192793
https://www.dongchedi.com/article/7598287774483202584
https://www.dongchedi.com/article/7598288632398856728
https://www.dongchedi.com/article/7598287158570435097
https://www.dongchedi.com/article/7598292330680418878
https://www.dongchedi.com/article/7598288380383855129
https://www.dongchedi.com/article/7598290710689219134
https://www.dongchedi.com/article/7598288042881073689
https://www.dongchedi.com/article/7598291946742317593
https://www.dongchedi.com/article/7598293637713478206
https://www.dongchedi.com/article/7598290400063373848
https://www.dongchedi.com/article/7598292454667944472
https://www.dongchedi.com/article/7598291773202776638

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 13:09:24

如何用perf_counter突破Cortex-M性能测量瓶颈?

如何用perf_counter突破Cortex-M性能测量瓶颈&#xff1f; 【免费下载链接】perf_counter A dedicated performance counter for Cortex-M systick. It shares the SysTick with users original SysTick function without interfering it. This library will bring new functio…

作者头像 李华
网站建设 2026/6/15 12:18:39

实战应用:使用verl完成Qwen2.5-0.5B的PPO训练

实战应用&#xff1a;使用verl完成Qwen2.5-0.5B的PPO训练 强化学习在大语言模型后训练中正从研究走向落地。当“用PPO微调小模型”不再只是论文里的公式&#xff0c;而变成你终端里跳动的日志、显存监控中起伏的曲线、以及最终生成更符合人类偏好的回答时——技术才真正有了温…

作者头像 李华
网站建设 2026/6/15 12:19:50

边缘设备也能跑TTS?Supertonic轻量化部署详细步骤

边缘设备也能跑TTS&#xff1f;Supertonic轻量化部署详细步骤 Supertonic 不是又一个“云端调用”的语音合成工具&#xff0c;而是一款真正为边缘而生的 TTS 系统——它不依赖网络、不上传数据、不调用 API&#xff0c;66MB 模型体积、ONNX Runtime 原生驱动、M4 Pro 上达 167…

作者头像 李华
网站建设 2026/6/15 11:22:15

Llama3-8B汽车维修指导:故障诊断助手部署教程

Llama3-8B汽车维修指导&#xff1a;故障诊断助手部署教程 1. 为什么选Llama3-8B做汽车维修助手&#xff1f; 你是不是也遇到过这些场景&#xff1a; 客户打电话来描述“车子启动时有咔咔声&#xff0c;但仪表盘没报警”&#xff0c;你得一边听一边翻手册查可能原因&#xff…

作者头像 李华
网站建设 2026/6/15 11:18:55

YOLO26分布式训练入门:DDP模式初步探索教程

YOLO26分布式训练入门&#xff1a;DDP模式初步探索教程 YOLO26作为新一代目标检测与姿态估计融合模型&#xff0c;凭借其轻量高效、多任务协同和强泛化能力&#xff0c;正快速成为工业部署与科研实验的新选择。但很多开发者在单卡训练跑通后&#xff0c;面对多卡加速需求时常常…

作者头像 李华
网站建设 2026/6/15 11:24:48

实测Whisper语音识别镜像:多语言转录效果超乎想象

实测Whisper语音识别镜像&#xff1a;多语言转录效果超乎想象 1. 引言&#xff1a;当语音识别遇上“全球通” 你有没有遇到过这样的场景&#xff1f;一段外语采访音频听不懂&#xff0c;会议录音密密麻麻记不下来&#xff0c;或者想把一段老外的播客内容翻译成中文却无从下手…

作者头像 李华