C++不同于C语言,是一门面向对象的语言,何为面向对象?简单来说,在C++中,开辟的空间,都能称为对象,类似C中的变量
C++入门,不同于C语言,知识点较零碎,而且每个环节联系较紧凑,我们务必要将前面的知识打扎实了,在接下来的类和对象才能柔韧有余
目录
重点是函数重载和引用
1、命名空间
在C++中,我们会接触到许多作用于全局的函数、类。它们作为一个独立的结构,有相应的变量名,为了防止函数、类中的标志被重复使用或改变,我们用namespace关键字来避免错误使用。
1.1、namespace定义
在namesapce空间中,可以定义变量,函数,也可以嵌套使用namespace,在这里类似于结构体 struct的使用,但不同的的是在结尾不需要在加分号; { } 中的项就是成员。
1.2、namespace的使用
这边一共展示了三种方法,在我们平时练习时,一般用第二种方法,可以节省重复操作;
而在工程,项目中,一把用第三种方法,避免分块编程造成的同名变量.
2、cout&cin
在C语言中有printf和scanf,在C++中有cin输入 和 cout输出
使用cin 和 cout 必须包含iostream 头文件和 std 标准命名空间
于c语言不通,c++ 中cout、cin能自动识别参数类型,不需要指定标识符(%c 、%d...),减少许多繁琐的操作。
3、缺省参数
3.1、概念
在声明函数时,可以对参数进行赋值,当调用函数时,传入参数不足时,使用声明中赋值的参数
3.2、全参数&半缺省
全缺省:
在函数声明时,参数全部是缺省,故传参可以为空
半缺省:
在函数声明时,参数从右往左连续是缺省参数,传参从左往右传.
注意点:
半缺省参数必须要连续缺省,不能跳跃
在函数声明和函数定义中,不能同时缺省
在C语言中不支持函数缺省
4、函数重载
函数重载,这块是面试中比较爱考的,要多花点心思,弄懂什么是函数重载,为什么C语言没有函数重载。
4.1、概念
函数名相同,函数(类型、个数、顺序)其中一个或多个不同就是函数重载
注意:
函数返回类型不同不属于函数重载
思考:为什么C++支持函数重载,而C语言不支持呢?
C++和C语言在很多方面都很相似,这个问题的根源在于编译的过程略有不同,
一个程序要执行,要经过预处理、编译、汇编、链接,我们简单复习一下这个过程
预处理:展开头文件,宏替换,去除注释
编译:检查语法问题,生成汇编语言
汇编:将汇编代码转成二进制机器代码
链接: 合并目标文件
而这个问题就出在链接环节的不同;
汇编生成机器代码(.o文件),在函数调用时,要转换成一个汇编指令,这个指令就是call;
比如有一个add.c文件,汇编成add.o
在main.o文件中调用函数,没有add函数的地址,但是事实上,我们先对main.c文件包含add.c文件,那么这个预处理指令下,程序就可以生成,在链接环节,链接器就需要在符号表中找到add.o函数的地址,如果函数名称一样,那符号表中就一样,在链接时就会出错。
而C++提出函数名称修饰;规则是 _Z(函数名符号个数)(函数名)(类型首字母)
例如 _Z3addi(int)c(char)
可见,相同的函数名称,在符号表中也可以不同;
main.o进行call add函数时根据参数生成 名称 在符号表中寻找。所以C++中参数的类型,顺序,个数,就可以决定符号表对应位置不同
总结:
C中call指令根据函数名称链接
C++则会生成函数名称,根据函数名称来链接;
4.2、C调用C++
在C++程序汇编时,同时会生成静态、动态库,C++程序则可以调用,而C语言由于call指令的链接方式不同,就无法使用C++静态库,为了解决这个问题,引入 extern"C",告诉编译器,该函数要按照c的规则来执行
5、引用
5.1、概念
在C++中我们会对变量取别名,而这个别名和该变量名效果相同,在内存中是同一块物理空间,
通过变量名,访问变量,通过别名访问变量;
用法: 类型&名称=实名
通过上面我们可以发现一个变量可以有多个别名,这些别名效果相当;
注意:引用时,一定要初始化
一个别名只能对应一个实体
指针能实现的,引用都能实现
5.2、常引用
如果我们想将它合法,可以在应用的类型前加上const修饰。
为什么可以呢?
在引用前加上const,别名变成只读,不可修改,那么不论别名是什么类型,也不会影响到原变量
也就是说别名的权限被缩小;
那么以下代码合法吗?
不合法;别名的权限将被扩大,那么会导致通过不同类型的别名修改变量,所以是不被允许的;
总结:
引用的权限只能缩小,不能扩大,通过const修饰别名,可以使别名成为只读;
5.3、引用的使用
1、作函数传参数
在C中,我们接触过传值,传址,在C++中。这里有第三种,传引用。
在参数传值中,实际上先对参数进行一个拷贝,然后再传,这时,参数是具有常性,只读不可修改;开辟了一块额外的物理空间
而传引用,没有开辟额外空间,传参数时,给参数取了别名,参数就是可读可改
2、作返回值
思考,这俩个程序为什么会有不同的结果呢?
原因在于static的修饰,延长了参数生命周期;
程序2中,局部变量n在栈区开辟了一块空间,一旦出了程序,局部变量就销毁,ret的值就保存2;
程序1中,第一次调用Count函数时,遇到声明static int n,在静态区开辟一个n,当函数结束了,栈区的数据被销毁,而静态区的n此时为2,没有被销毁,当再一次进入Count函数,由于n已经声明过了,就会跳过定义n的那行代码,就是说,n的值从2开始加;
从中呢,我们会发现引用的不安全性,一旦局部函数结束,要保存某个数或者再使用,要用上static修饰的传值返回
如果局部函数结束,空间就还给系统,用传值返回
5.4、引用的意义
不需要额外开辟空间,提升程序运行的效率;
5.5、引用和指针
在语法概念上,引用不开空间,指针开空间,而实际底层上,引用要开空间,引用通过指针来实现;所以在指针能实现的场合,引用都能实现
引用和指针的区别:
1、指针定义时可以不初始化,引用必须初始化;
2、没有空引用,但有NULL指针;
3、引用在指定一个实体后,不能再指定其他实体;指针在赋值后,可以在赋值;
4、有多级指针,没有多级引用;
5、引用比指针更安全;
6、内联函数inline
有一个add函数,在main()函数中要频繁调用,每次调用函数,都要进行压栈、出栈操作,占用特别多时间,因此C和C++都提出解决方案
C用宏 但是宏,在预处理时,机器将宏展开,而宏有自身的缺点,不方便调试,可读性差;
所以C++在变量定义时引入const
在函数定义时引入内联inline ; 在函数定义时,在返回值前面加上inline 告诉编译器,在调用时直接展开函数,不经历压栈出栈操作;是典型的以空间换时间方法
注意:
inline适合代码较短的函数,递归、长的函数不适合用内联;
inline 对编译器只是建议,实际上是否会在调用时直接展开,还是要看编译器的判断;
inline 一般定义和声明不分离,否则会造成链接错误;
7、auto关键字(c++11)
auto自动推导对象类型;
注意:
auto不能用在函数参数中;
auto使用必须初始化;
auto不能用来推导数组类型;
8、语法糖:范围for
在C++11中,快速遍历数组,提供了一种方法__范围for
9、nullprt
在C++中,空指针推荐用nulltrt取代NULL;
它们都表示0;且定义都是宏实现
经过宏定义 NULL为0;是整形
而宏定义nlllprt为 ((void*)0) 本质是整形指针
所以在后续的使用,用nullprt代替NULL;