【C++学习笔记】----(命名空间,缺省参数,重载,引用,内联函数,auto,空指针,extern)

1.命名空间

(1).概念

C语言是将库函数封装在头文件中,我们在对变量等命名的时候不能和库函数的一样,例如printf。所以C++中为了避免这个问题,引入命名空间的概念,即:某个命名仅仅在它的命名空间起作用,通过这个很好的将同名问题解决了。

(2).命名空间的定义

namespace N
{
//变量
int a =10;
//函数
}
1.直接定义
2.可以嵌套
3.同一工程下同名命名空间会合并。

(3).命名空间的使用

1.通过作用域限定符 ::
N::a声明a是属于N这个命名空间的
2.使用using将命名空间的变量引入
using a
3.使用using namespace 将命名空间引入
using namespace std
将std库打开,那么这个就会退化为C中的用法。不能定义同名,但是使用方便,不用限定范围。

2.缺省参数

(1).概念

缺省参数是声明或者定义函数时为参数指定一个默认值,如果没有指定实参,就使用缺省的参数值,如果指定实参,那么缺省参数不生效。

void TestFunc(int a = 0) {
 cout<<a<<endl; }
int main()
{
 TestFunc(); // 没有传参时,使用参数的默认值
 TestFunc(10); // 传参时,使用指定的实参
}

(2).缺省分类

全缺省

void TestFunc(int a = 10, int b = 20, int c = 30) {
 cout<<"a = "<<a<<endl;
 cout<<"b = "<<b<<endl;
 cout<<"c = "<<c<<endl; }

半缺省

void TestFunc(int a, int b = 10, int c = 20) {
 cout<<"a = "<<a<<endl;
 cout<<"b = "<<b<<endl;
 cout<<"c = "<<c<<endl; }

半缺省只能从右向左缺省。
定义和声明不能同时出现缺省值,因为可能造成编译器无法确定使用哪一个值。

3.重载

(1)概念

重载是函数使用的特殊情况,也就是使用同名函数。
这个在C语言中是不支持同名函数的,因为在最后链接时,是通过符号表去找相应的函数地址,C语言是通过函数名去找地址,所以同名函数会造成编译器不知道调用哪个函数。

在C++中,符号表存储函数的时候是Z+函数名字母个数+类型。
例如Add(int a,int b) --> Z3Addii
这样就可以将同名函数区分出来,实现重载。

需要注意的是,重载必须是同名函数,参数的类型或者个数,或者顺序,任意一个不同才可以。通俗的说,就是让它们在链接器链接的时候能区分调用的函数。所以void add(int a,int b)和void add(int b,int a)不能发生重载,因为它们的命名都是Z3addii。

(2)程序运行的几个阶段

这里来回忆一下程序运行的几个阶段
预处理:头文件展开,宏替换,去注释,条件编译等

编译:检查语法错误,生成汇编代码。

汇编:将汇编代码转化为二进制指令

链接:将几个目标文件链接起来,形成可执行的文件。

4.引用

(1).概念

引用就是别名,实现的作用就是对原来地址空间的数据进行操作,和指针差不多,底层实现依靠指针,以交换数值为例子。

(2).区别

和指针的区别,通过指针的话,需要新开辟两个临时空间储存地址,然后通过地址完成交换,最后释放地址空间。

和直接交换的区别,我们如果直接在main函数里面完成交换,和引用就一样了。如果通过调用函数来完成,那么新开了空间直接存数据,改变这个地址下面的数据,对原有的空间数据没有影响,是不能完成交换的。

有多级指针,没有多级引用。

指针需要解引用,引用编译器自己处理。

引用始终和原有类型相同,而指针是地址空间占用的字节大小。

引用比指针更安全。

(3).特性

1.引用必须初始化,而指针不需要初始化。
2.引用类型和引用实体必须是同类型的,但是不同类型的引用,例如最后一个,这里是新开了一个空间将d的值存储起来,然后在引用这个区域。所以这个空间的值是不可以改变的。这里要用const来实现引用的权限限制。
3.引用一旦引用一个实体,就不能引用其他实体。
4.引用时权限可以缩小,但是不能放大。

void TestConstRef()
{
 const int a = 10;
 //int& ra = a; // 该语句编译时会出错,a为常量
 const int& ra = a;
 // int& b = 10; // 该语句编译时会出错,b为常量
 const int& b = 10;
 double d = 12.34;
 //int& rd = d; // 该语句编译时会出错,类型不同
 const int& rd = d; 
 }

(4).应用场景

1.做参数

void Swap(int& left, int& right) 
{
 int temp = left;
 left = right;
 right = temp;
  }

2.做返回值

int& Count()
{
 static int n = 0;
 n++;
 // ...
 return n; 
 }

注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

5.内联函数

(1).概念

以inline修饰的函数叫做内联函数,调用内联函数,直接展开,减少压栈的开销,提升了运行效率。但是内联函数必须是相对简单的代码,本质上是一种以空间换时间的做法。

(2).和宏的区别


优点:代码可以复用,提高性能
缺点:没有类型安全检查
不方便调试,在预处理就被替换了
代码可读性差
C++中 常量定义 使用const修饰
函数定义使用内联函数。

inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。

6.extern “c”

在C++编译过程中,有的函数需要以C的风格编译,我们通过声明,告诉编译器,这里使用C语言的语法编译。在符号表的命名就会以C语言的方式去命名。

7.auto

(1).概念

auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得,由后面的类型直接推导出前面变量的类型。

(2).注意事项

1.使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

2.用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&

3.auto不能作为函数的参数

4.auto不能用来声明数组

5.使用auto时,同一行的类型必须相同。

8.NULL和nullptr

NULL实际上是一个宏。
在这里插入图片描述
在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下
将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。
为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr

9.for

for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,比原来写法简洁了许多。

void TestFor()
{
 int array[] = { 1, 2, 3, 4, 5 };
 for(auto& e : array)
 e *= 2;
 
 for(auto e : array)
 cout << e << " ";
 
 return 0; 
 }

注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。

初学C++,担心自己猴子搬玉米,所以写一点笔记,如果有错误,欢迎留言指导,一起进步!!!

发布了79 篇原创文章 · 获赞 6 · 访问量 3763

猜你喜欢

转载自blog.csdn.net/qq_41152046/article/details/105336439