C++基础语法(1)
1.C++入门
一、命名空间
定义:
- 定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
- namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量,所以下⾯的rand不在冲突了。
- C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的⽣命周期,命名空间域和类域不影响变量⽣命周期。
防止自己跟库、自己跟自己命名的变量、结构、函数发生冲突
(1)命名空间的定义
格式:
namespace [空间名字]
{//变量、类型、函数
}
注意:
- 格式上与结构体很像,但大括号
{}
的最后没有分号;
- 命名空间内可以定义变量、函数、类型等;
- 命名空间可以嵌套,但要注意是把整个命名空间完全嵌套在另一个命名空间内
- 该方式定义的是一个命名空间,而不是结构,不可以重命名
- 在同一个项目中的不同文件,或同一个文件中可以存在多个相同名称的命名空间,此时在程序执行的时候,同名的命名空间会被整合到一起
- 不可以在函数内部创建命名空间
(2)命名空间的使用
变量、函数、结构在使用之前可以用关键字[域名]::
来标记这个变量、函数、结构来自哪里。
- 不含制定访问命名空间的情况
- 如果写了关键字
::
- 如果域名为空,则表示来自全局域
- 如果写了域名,则表示来自这个域这种情况不属于不含制定访问命名空间的情况但这里还是提一下
- 注意此时如果在这个域里面没有找到,不会到其他域里面去找
- 如果不写关键字
::
- 程序会按照以下顺序查找变量所在域(谁先找到就用谁):使用位置所在域—>全局域==(注意:不会去命名空间域去找)==
- 如果写了关键字
- 含指定访问命名空间的情况
- 1>指定访问命名空间的方法:
- 展开命名空间–>
using namespace[域名]
–>使用位置所在域(局部域)–>指定访问命名空间域
(如果在全局域和指定展开域都存在该变量名,会报错–>'x’不明确) - 展开命名空间变量–>
using [域名:变量]
–>全局域–>指定访问命名空间域的指定变量,其他变量不受影响
(如果局部域和展开命名空间变量都存在该变量名,会报错–>using声明导致多次声明)
- 展开命名空间–>
- 1>指定访问命名空间的方法:
代码示例:
namespace name
{namespace name2{int rand = 0;int sub(int x, int y){return x - y;}typedef struct{int n;char* ph;}ST;}
}namespace name
{mamespace name1{int rand = 0;int add(int x, int y){return x + y;}typedef struct{int n;char* ph;}ST;}
}
有几点需要注意:
- 变量创建在局部域还是全局域会影响变量的生命周期,但在命名空间中定义的变量生命周期就是在全局范围
- 对于上一条的第二句话的理解基本正确,但需注意两点:
- 命名空间中的变量默认具有全局生命周期,但若显式声明为
static
,其作用域会被限制在命名空间内,但生命周期仍为全局。 - 命名空间域本身不影响生命周期,而是通过变量的存储类别(如
static
或非static
)间接决定生命周期。
- 命名空间中的变量默认具有全局生命周期,但若显式声明为
代码运行展示:
二、C++的输入输出的简单使用
-
C++使用**cout标准输出对象(控制台)和cin标准输入对象(键盘)**时,cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,必须包含
<iostream>
头文件以及按命名空间使用方法使用std。在<iostream>
中cout,cin,endl这些对象都包含在一个叫std的命名空间中,所以在使用的时候,我们需要按照前面命名空间的使用规则使用cout与<<,cin与>>要成对使用,可以连着用,可以像C语言一样输出/输入字符串,变量等等
-
<<是流插入运算符,>>是流提取运算符。
-
C++兼容C,因此可以在C++文件中使用之前学的C的输入函数与输出函数,但要注意:
<iostream>
可能包含了C中的部分头文件,但不同的编译器可能不同,使用时多加注意,但使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。 -
注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文件不带.h;
std命名空间的使用惯例:
std是C++标准库的命名空间,如何展开std使用更合理呢?
1.在日常练习中,建议直接usingnamespace std即可,这样就很方便。
2.usingnamespacestd展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。所以建议在项目开发中使用,像std:cout这样使用时指定命名空间+usingstd:cout展开常用的库对象/类型等方式。
三、缺省参数
缺省参数是在函数声明或定义的时候为函数中的形参提供一个可供参考的缺省值,如果函数在使用的时候没有指明实参,则采用缺省值,如果指明实参则采用指定实参缺省参数的分类:全缺省(函数在定义后或声明的时候所有的形参都是缺省参数)和半缺省(只有一部分形参是缺省参数)
注意:
- 如果为半缺省的情况,缺省参数只能从右往左依次给出,不可以间断
- 缺省参数不能在函数定义和函数声明中同时存在,因此缺省参数最好给在函数声明中
- 缺省值必须是全局变量或常量
四、补充解释
-
命名空间的展开是指在展开的域中,可以去指定的命名空间中查找变量了,并不是说展开之后指定命名空间的变量的作用域就在全局或其他域中去了
-
如果同时展开多个命名空间,可能会发生冲突:如果被展开的两个命名空间定义了同一个变量名,在不指定域的情况下使用该变量名
就会产生访问歧义但并不是说多个命名空间不能同时展开,在指定域的情况下,是可以同时展开使用的
五、函数重载
C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔是不⽀持同⼀作⽤域中出现同名函数的。
在同一个域中,可以存在函数名相同但定义不同的多个函数,构成函数重载,函数重载需要满足以下条件:
-
这几个函数的形参变量的个数不同或类型不同,或顺序不同
-
函数重载与函数返回值,函数形参名,是否为缺省形参无关
示例一:只是返回值类型不同的函数不能构成重载 -
函数重载会有一种特殊情况导致不兼容:如果在同一个域中定义了一个
fun()
和一个fun(inta=10)
,然后我们调用fun()
虽然这两函数满足函数重载的条件,但是在程序运行的时候仍然无法通过,这种特殊情况区别于其他的关键是形参:一个没有形参,一个为只有缺省形参//他们俩构成函数重载,但是无参调用时会存在歧义
这种特殊情况仍然构成函数重载,但是程序不能正常运行。如果没有进行调用,程序可以编译通过
几个典型的错误:
查看图片的时候注意标注
C++可以实现函数重载的原理----函数名修饰
- 在前面的C语言课程中,我们学了一个项目中的文件要经过预处理,编译,汇编,链接等过程才能生成可以直接运行的.exe程序。
- 其中,如果某个函数的定义和声明不在同一个文件中,在连接之前,只有声明的那个文件找不到这个函数的真正地址(在函数定义中,一般是函数的第一条指令的地址),所以链接阶段链接器看到文件调用这个函数,但是没有这个函数的地址,就会到另一个文件的符号表中找这个函数的地址,然后链接到一起。此时符号表中的函数名会被修饰,即便是同名函数,在c++中满足函数重载的函数修饰后的函数名不同,从而c++可以实现函数重载,但由于c中没有函数名修饰,因此c语言不支持函数重载
在c++中满足函数重载的函数修饰后的函数名不同,从而c++可以实现函数重载**,但由于c中没有函数名修饰,因此c语言不支持函数重载
[外链图片转存中…(img-ziblHRD8-1744714398248)]
[外链图片转存中…(img-NY3uwfrs-1744714398248)]