C++新手入门学习教程_c++教程

C++新手入门学习教程_c++教程目录 前言 一 C 语言与 C 1 C 语言和 C 的关系 2 C 的代码实现 编译器 Dev C 5 11 二 命名空间 1 命名空间存在的意义 2 关键字 namespace 3 域作用限定符 nbsp 与命名空间 4 命名空间的使用 5 C 输入与输出 三 缺省参数与函数重载 1 缺省参数 2 函数重载 四 引用与指针 1 引用的概念 定义 特性 2 引用的作用 3

大家好,我是讯享网,很高兴认识大家。这里提供最前沿的Ai技术和互联网信息。



目录

前言:

一、C语言与C++

1. C语言和C++的关系

2.C++的代码实现(编译器Dev-C++ 5.11)

二、命名空间

1.命名空间存在的意义

2.关键字namespace

3.域作用限定符 :: 与命名空间

4.命名空间的使用

5.C++输入与输出

三、缺省参数与函数重载

1.缺省参数

2.函数重载

四、引用与指针

1.引用的概念、定义、特性

2.引用的作用

3.const引用

4.指针与引用的关系

五、宏函数与inline

1.宏函数

2.inline

六、NULL与nullptr

1.NULL

2.nullptr


前言:

建议:本文章阅读前应具备一定的C语言基础!

欢迎来到这篇C++核心入门指南!
本文旨在为你清晰地揭示C++在C语言基础上的核心扩展与思想变革。通过对比学习,你将能更深刻地理解C++为何而生,以及它如何通过一系列新特性来解决更复杂的问题。

本文的讲解会频繁与C语言特性进行对比。熟悉指针、函数等C语言核心概念,将帮助你无缝衔接,更好地领悟C++的设计哲学与强大之处。

在接下来的内容中,我们将重点探讨以下六个关键主题,它们构成了从C迈向C++的基石:
• C语言与C++:剖析二者的血缘联系与根本区别,理解C++“兼容C”与“超越C”的双重特性。
• 命名空间:学习如何组织代码,避免大型项目中的标识符命名冲突。
• 缺省参数与函数重载:掌握让函数接口更灵活、更易用的两种强大机制。
• 引用与指针:深入理解C++中引用的本质,并理清它与指针的异同及适用场景。
• 宏函数与inline:探索C++如何用更安全、更高效的内联函数来替代C语言中的宏定义。
• NULL与nullptr:了解为何现代C++要引入nullptr来取代传统的NULL,以增强类型安全。

















• 平常我们看到的“C/C++”这种写法是为了强调它们的紧密联系和共生关系,而分开写则是为了强调它们作为独立语言的根本区别。C++是在C语言的基础上发展而来的,C++语法高度且单向兼容了C(在C++源代码文件里可以使用C代码),但是还是存在一些细微差别。

• 当然C++基于C语言也并不代表C++相较于C在设计上保持全面领先,C++在提供强大抽象能力的同时在一些设计上相较于C语言做出了取舍,但同时优化了C语言的某些方面。所以在具体的使用上,C和C++根据使用场景选择。

• 首先C++和C首先说明不同的点是文件后缀名,C语言的源代码文件后缀是.c,而C++的源代码文件后缀是.cpp。我们知道C++兼容C,所以在C++中我们依然可以使用C,代码如下:

C++新手入门学习教程_c++教程_#开发语言

  如上图中所示:在.cpp后缀的文件中,还是可以使用C代码,并且顺利编译。

C++拥有一整套区别于C语言的、独立且丰富的语法体系。这些新语法不是对C的简单修补,而是为了支持全新的编程范式和更安全的编程实践而创建的。接下来展示区别于C语言的,C++的第一个程序“hello world!”,让我们看看它的的代码:

C++新手入门学习教程_c++教程_编译器_02

上图中,我们可以看到很多以前在C语言中没有遇见的“新玩意”,接下来我会循序渐进的分别对这些进行讲解。


• 在写C程序的时候,多个不同模块/库的全局标识符(全局变量、全局函数)若同名,会产生命名冲突(编译/链接会报错)。C++的解决方案:通过namespace,隔离全局作用域下的同名标识符,从而解决这种命名冲突。

C++新手入门学习教程_c++教程_编译器_03

在C语言中我们定义了一个名为printf的函数,但是stdio.h又包含名为printf的库函数,这时就会产生命名冲突,导致程序报错。

C++新手入门学习教程_c++教程_编译器_04

当把函数名改成print后,程序可以正常运行,可是在实际项目中,工程量是非常大的,过程中是难以避免出现命名冲突的,为此我们需要使用到关键字namespace

• 定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,后面再写上一对 { } 括号, { } 中便是命名空间的成员。命名空间中可以定义变量/函数/类型等。

C++新手入门学习教程_c++教程_命名空间_05

上图示例中,我使用namespace关键字定义的名为gth的命名空间,并在命名空间内定义了一个整形的变量num,和一个无返回类型的函数printf。

• namespace本质是定义出一个域,被称为:命名空间域,这个域跟全局域各自独立,不同的域可以定义同名变量,同一个域不能定义同名变量。

C++新手入门学习教程_c++教程_缺省参数_06

同一个域内依然会出现命名冲突,执行时程序发出警告。

• C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找一个变量/函数/类型出处(声明或定义)的逻辑,所以有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的声明周期,命名空间域和类域不影响变量声明周期。

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

C++新手入门学习教程_c++教程_#开发语言_07

 上图中可以看到一共定义了三个域分别是:gth,a,b。而域a和域b又嵌套在gth内的,它俩都定义了整形变量num却又互不影响,因为它们属于不同的域。

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

C++新手入门学习教程_c++教程_#开发语言_08

C++新手入门学习教程_c++教程_缺省参数_09

可以看到上图中即使在不同的文件里,即使定义相同的域名,但是依然可以编译。它的本质是被默认认为是同一个域,有些小伙伴可能会有一个疑问:那不同文件下定义的同名的域内成员之间会不会产生命名冲突?答案是会的,请看下图:

C++新手入门学习教程_c++教程_编译器_10

当我把main.cpp下gth内定义的变量名改成a时,它便和头文件下gth内定义的变量名产生命名冲突。由此,加深我们对命名空间的理解:命名空间的出现较大的避免了产生命名冲突的可能性,但这种可能性是一直存在的,此外,我们还可以合理的利用命名空间的嵌套性。

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

C++新手入门学习教程_c++教程_缺省参数_11

我们已经知道了std是C++中封装标准库的命名空间了,namespace是定义命名空间的关键字,那么在上图,那一行代码中为什么多了个using?当然这里一定不是定义命名空间std,那它扮演着怎样的身份?以及被命名空间封装后有什么变化,应该怎么使用?下面答案都会慢慢揭晓。

• 在C++中域作用限定符 ::(两个连续的英文冒号) ,是用来明确变量、函数、类型等所在的作用域。

C++新手入门学习教程_c++教程_命名空间_12

  我们可以看到,当我输出变量a的时候,在它前面加上了 :: ,并且在 :: 前面加上了名为gth的域。这其实相当于告诉编译器调用的是gpt域里面定义的变量a。这里可能又有小伙伴疑惑了,为什么这里的命名空间内的变量需要加::,而前面调用C++标准库时却没有使用到std,这种就得讲解到using的时候就清楚了。

• 当 :: 的左边什么都不写默认是在全局域。

• 当 :: 左边跟上命名空间的名字,则是在该命名空间域内查找。

• 命名空间内定义结构体,使用时需要在struct关键字后结构体类型名的前面加::,因为在C++中struct定义的类名可以直接作为类型名来使用,使用类型名的时候不在需要加上struct了。

C++新手入门学习教程_c++教程_命名空间_13

  以上代码中可以看到两个同名的data,因为在不同的域内,所以它们不会有命名冲突。分别用他们定义了p1和p2,并没有在data前面加struct,这也是在C语言基础上的一个优化。注意:对命名空间域内进行操作时,记得加域作用限定符::。

• 指定命名空间访问,项目中推荐这种方式。

C++新手入门学习教程_c++教程_编译器_14

• 利用using 将命名空间中某个成员展开,项目中经常访问的不存在冲突的成员推荐这种方式。

C++新手入门学习教程_c++教程_#c++_15

  展开后使用该成员便可以不用加域作用限定符了。这里就对变量a进行展开,但是使用变量b时还是要加gth:: 。

• 展开命名空间中全部成员,项目不推荐,冲突风险很大,日常小练习程序为了方便使用。

头文件中禁止使用。

C++新手入门学习教程_c++教程_缺省参数_16

  对比上一个使用方式,这种是将整个域内成员进行展开,展开范围变广,且使用using时后面加了个namespace。

• 展开头文件和展开命名空间的区别:

展开头文件,仅发生在【预编译阶段】,是纯文本拷贝操作,同时只拷贝声明,不会拷贝函数的实现代码。

展开命名空间,相当于原本命名空间里面标识符被人用锁链拴住了,调用它需要用相符合的钥匙(域名+域限定符)把他解开,而展开后不再需要钥匙打开了,标识符身上了锁链消失了。

• 相比于C语言,C++也有着自己的输入输出(cin、cout),可以自动识别数据类型,在使用上更加方便安全。支持链式操作,无需指定格式符。(需要和< <和> >运算符搭配使用,当< <和> >遇见它们时就变成了流运算符)

C++新手入门学习教程_c++教程_编译器_17

流运算符右边一次只能操作一个操作数,一行可以使用多个流运算符。除此外我们还看到endl和 ,它俩都用于换行,区别: 只支持换行,endl功能是插入换行符并强制刷新输出缓冲区。

是Input Output Stream的缩写,是C++中的标准的输入、输出流库,定义了标准的输入、输出对象。

• std::cin是istream类的对象,它主要面向窄字符(narrow characters(of type char))的标准输入流。(窄字符在后续文章会扩展讲述)

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

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

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

• 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动指定格式,C++的输入输出可以自动识别变量类型(本质是通过函数重载实现的,后续补充),其实最重要的是C++的流能更好的支持自定义类型对象的输入输出。

• 在io需求比较高的地方,如部分大量输入的竞赛题中,在 函数的开头加上以下3行代码可以提高C++io效率,你的 /速度就会非常接近甚至超过 /,同时保留了C++ I/O类型安全的优点。

ios_base::sync_with_stdio(false)

cin.tie(nullptr);

cout.tie(nullptr);

  或者可以直接用scanf/printf。cin/cout像一套智能、安全的现代化工具,而 printf/scanf则像一套需要高超技巧但极限效率更高的手动工具。

• 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参,则采用该形参的缺省值,否则使用指定的实参,缺省参数分为全缺省和半缺省参数。(有些地方把缺省参数也叫默认参数)

C++新手入门学习教程_c++教程_#开发语言_18

  上图中,定义add函数的时候给x变量赋了一个缺省值为10,当我第一次使用add函数时,就传了一个值给y,并没有传值给形参x,那么形参x就用自己的缺省值10;而当我第二次使用add函数时,两个形参都传了值,那么形参x便使用传过来的值20。

• 全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次缺省,不能间隔跳跃给缺省值。

C++新手入门学习教程_c++教程_缺省参数_19

  定义函数时,括号内左边无缺省值,右边有缺省值,不能中间互相穿插。

• 带缺省参数的函数调用,C++规定必须从左到右依次给实参,不能跳跃给实参。

• 函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。(因为如果在函数定义时出现缺省参数,那么别人不知道便会报错)

C++新手入门学习教程_c++教程_编译器_20

• C++支持在同一作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是形参个数不同或者形参类型不同。这样C++函数调用就表现出了多态行为,使用更灵活。C语言是不支持同一作用域中出现同名函数的。

C++新手入门学习教程_c++教程_#c++_21

以上代码中有三个同名的函数greet,在C++中是可以区分这三个函数的,因为这三个函数的形参在使用时根据实参的个数或者类型就可以精准的调用哪个函数。

C++新手入门学习教程_c++教程_#c++_22

  上图是代码执行结果,可以看到程序是可以编译并执行的。

定义两个构成函数重载的函数时,当这两个函数分别为无参和全缺省时,调用会存在歧义!!!


• 引用的标识符是&(与符号),要紧跟类型名后才表示声明的是一个引用(别名)。

C++新手入门学习教程_c++教程_缺省参数_23

 如上代码中,定义了一个变量a,还定义了一个引用b并同时将a赋值给b。

• 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。(下面我们来观察一下如上代码的执行结果)

C++新手入门学习教程_c++教程_#c++_24

  可以看到,a和b的值是一样的,并且a和b的地址也是一样的,代表它并没有为b开辟新的内存空间。

• 引用在定义时必须初始化,一个变量可以有多个引用,引用一旦引用一个实体,再不能引用其它实体。

C++新手入门学习教程_c++教程_编译器_25

  如上代码中,变量a被c和d引用两次,不仅如此,引用本身也可以再次被引用。注意:我们必须在定义引用的时候赋值,也只能在定义引用的时候赋值。

• 不同类型的变量和引用,该变量是不能被该类型引用取别名的。

C++新手入门学习教程_c++教程_#开发语言_26

  因为a是char类型,而b是int类型,类型不同,所以a不能被b引用。

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

C++新手入门学习教程_c++教程_编译器_27

• 引用传参跟指针传参功能是类似的,引用传参相对更方便一些。

• 引用返回值的场景相对比较复杂,后续类和对象章节深入了解。

• 引用和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引用跟其他语言的引用(如Java)是有很大的区别的,除了用法,最大的点。C++引用定义后不能改变指向,Java的引用可以改变指向。

• 在C++中,const引用(对常量的引用)主要用来为变量创建一个只读的别名。它结合了引用的高效和const的安全性,允许你以只读方式访问变量,无法通过这个引用修改其绑定的值。声明const引用时,在引用符号前加上关键字。一旦绑定,就不能通过这个引用修改目标对象的值。

C++新手入门学习教程_c++教程_#开发语言_28

  以上代码中,变量a的权限是可读可写,引用b的权限为只读,这赋值过程属于权限缩小。

• 可以引用一个const对象,但是必须用const引用。const引用也可以引用普通对象,因为对象的访问权限在引用过程中可以平移或缩小,但是不能放大。(可写可读>只读)

C++新手入门学习教程_c++教程_命名空间_29

  引用b为权限为只读,被赋予一个可读可写的变量时,这一过程属于权限放大,导致程序报错。

• 其次我们还要了解一个概念:临时对象。所谓临时对象就是编译器在需要时自动创建的、没有名字的匿名对象,C++中把这个未命名对象叫作临时对象。临时对象具有常性,即它的访问权限是只读的,所以临时对象都能被const引用,接下来我们展示几个临时对象的诞生场景:

• 函数的返回值,返回值本身就是一个临时对象。

C++新手入门学习教程_c++教程_命名空间_30

• 隐式类型转换,不同类型的变量进行传值时会发生隐式类型转换,在发生隐式类型转换的过程中会创建一个临时对象,那么const引用可以对该临时对象取别名。

C++新手入门学习教程_c++教程_#c++_31

• 表达式求值,当几个变量进行运算,编译器自动创建,用于存储计算结果的临时对象。

C++新手入门学习教程_c++教程_#开发语言_32

• 常量,const引用可以对常量取别名,因为这种引用属于会创建临时对象存储常量。

C++新手入门学习教程_c++教程_缺省参数_33

临时对象被const引用后,生命周期开始跟着引用走。

• C++中指针和引用功能上有重叠性,但是各有自己的特点。

• 语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量地址,要开空间。sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址所占字节个数(32位平台下占4个字节,64位下是8byte)。

C++新手入门学习教程_c++教程_缺省参数_34

• 引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。引用在初始化时引用一个对象后,就不能再引用其他对象;指针可以不断地改变指向对象。

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

• 在赋值过程中汇编代码上它俩的操作是类似的。

• 指针很容易出现空指针和野指针的问题,引用使用起来相对更安全一些。

 • C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不方便调试,C++设计了inline目的就是替代C的宏函数。下面来看看正确的简单宏函数的实现。

C++新手入门学习教程_c++教程_编译器_35

• 用inline修饰的函数叫作内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要建立栈帧了,就可以提高效率。属于空间换时间。

C++新手入门学习教程_c++教程_编译器_36

• inline对于编译器而言只是一个建议,也就是说,你加了inline编译器也可以选择在调用的地方不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适用于频繁调用的短小函数,对于递归函数、代码相对多一些的函数,加上inline也会被编译器忽略。

 由于宏是纯文本替换,需要时刻注意运算符优先级,相对易出错。

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

C++新手入门学习教程_c++教程_#开发语言_37

C++新手入门学习教程_c++教程_编译器_38

C++新手入门学习教程_c++教程_#c++_39

错误案例具体代码如上,内联函数的定义必须在调用它的编译单元中可见,否则编译器无法完成“代码替换”,且会导致链接错误。一般建议内联函数定义在头文件中,以避免这种错误。

• 编译器debug版本下默认是不展开inline的,这样方便调试。

C++新手入门学习教程_c++教程_编译器_40

可以看到编译器提供了很多个版本:

Release(发布版):用于生成最终可执行程序。

Debug(调试版):用于在开发过程中调试程序。

Profiling(分析版):用于分析程序性能瓶颈。

• inline时建议性关键字(不是强制),具体该函数是否展开由编译器决定。展开的核心目的是减少函数调用的开销,提升程序运行效率。


编译器:Visual Studio 2026 18.1.1

• C++中NULL一般被定义为字面常量0,或者C中被定义为无类型指针(void)。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦。(以下代码在Dev-C++ 5.11编译器中不支持,所以以后开始使用Visual Studio 2026 18.1.1)

C++新手入门学习教程_c++教程_#开发语言_41

想调用add(int y);却因为NULL被定义为0,导致调用了add(int x);与初衷相悖。

• 在C语言中void类型的指针是可以不强制类型转换赋值给任何类型的指针(因为隐式类型转换了)。但是C++不再支持了,需要强转为对应类型指针

C++新手入门学习教程_c++教程_#c++_42

强制类型转换成void*后程序会报错,这主要是C++为了增强类型安全和支持函数重载而设计的。

C++新手入门学习教程_c++教程_#c++_43

当强制类型转换为int*后,程序便可以正常运行了,函数被精准执行。

• C++11中引入nullptr,nullptr是一个特殊的关键字,nullptr是一种特殊类型的字面量,它可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr支持被隐式转换为指针类型,而不会被隐式转换为整数类型。

C++新手入门学习教程_c++教程_编译器_44


以上,我们从C++的起源与实现环境出发,逐步探讨了命名空间、缺省参数、函数重载、引用与指针等核心特性。这些不仅是C++语法的基础,更是其“面向对象”与“泛型编程”强大能力的底层支撑。理解这些概念,意味着您已迈出了从C语言思维向C++抽象思维转变的关键一步。编程之路,道阻且长,行则将至。愿您能将这些知识内化为坚实的基石,在后续面向对象、模板、标准库等更广阔的世界中,构建出高效而优雅的代码大厦。

小讯
上一篇 2026-03-20 21:19
下一篇 2026-03-20 21:17

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/240976.html