首先的话是cpp兼容c
首先的话是namespace
这是一个相当的关键,项目的C语言时候是有很多的命名冲突
因为多个的文件之中的话很容易项目名字重复
命名空间本质是一个封装盒子,将所有的自己需要的变量和函数,将每一个自己需要工作的分割开来(C语言之中强调的是局部和全部)
这个是影响的查找,比如一个变量的查找,先是局部的查找,在世全局去查找,预处理阶段
而隔离开了之后是直接到相应的地方查找,另外一个就不会去找了
生命周期是销毁的时间,namespace不会去影响
举例是一个项目组之中各种常用的名字各自封装,之后用的时候
这时候导入域作用限定符::,这个就是寻找是直接到相应的去找,类似于去不同楼层去找相同的门牌号,
namespace仅在全局
namespace之后不可以跟;
namespace可以嵌套,n里面包裹n,全局里面还是全局,使用时,n1::n2::r,这样的话就类似于不同的小区找相同的楼的相同门牌号
定义的struck的定义的是名字,引用的时候限定符号还是跟在名字前面,struct后面
名字相同的namespace会自动合并,所以项目时候保证自己的namespace之中不冲突就可以
题外话:给一个头文件就是为了给一个目录,方便之后改,分成不同的文件,方便之后改
cpp的命名空间是放在std之中(所有的文件名字)
命名空间的使用,
指定命名空间,一个一个打,严谨但是很麻烦
可以using namespace(影响查找规则,查找的时候到这里去查找,类似于把封装的盒子爆了) 这个分为两个方面,一个是展开一部分,一个是展开全部(一个是全开了,一个是正常情况用的最多的全部展开)
cpp之中头文件可以不包括.h
输入输出
输入输出printf 还有scanf的有指定的类型,有局限性
cin输出,cout输入,将所有的字符转化成窄字符之后再搞
endl是换行还有刷新缓冲
>>输出,<<输入,插入
自动识别类型,连续的输入输出
换行的话就是后面跟一个<<endl,效果跟好一些吧
iostream是包括了c之中全部的头文件(VS之中包括)
按照水流方向去认知
控制小数点位数的话直接就是还是用c的,cpp有点麻烦
缺省函数
C语言之中不接受
也就是如果没有给参数直接调用那么就是用给的默认的参数
全缺省和半缺省就是全部都是用默认值
缺省不可以跳跃的传递
这里需要知道的就是这是规则,语法就是
缺省参数还有半缺省,传至少一个,可以从前到后一个一个传
函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省 值
函数栈帧里面的压参是编译层,但是这里讲的是语法
函数重载
C语言里面不允许同名函数存在
C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者 类型不同
引用
引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间, 它和它引⽤的变量共⽤同⼀块内存空间
类型&引⽤别名=引⽤对象;
引⽤在定义时必须初始化
⼀个变量可以有多个引⽤
引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体(也就是一个外号不可以给两人)
使用场景
引⽤在实践中主要是于引⽤传参和引⽤做返回值中减少拷⻉提⾼效率和改变引⽤对象时同时改变被 引⽤对象。
引用场景:相当形参是实参的别名
void Swap(int& rx, int& ry)
{
int tmp = rx;
rx = ry;
ry = tmp;
}
int main()
{
int x = 0, y = 1;
cout << x <<" " << y << endl;
Swap(x, y);
cout << x << " " << y << endl;
return 0;
}
改变指针需要传递指针的指针,也就是二级指针
这里就业可以给指针取别名,引用一级指针代表直接就可以对指针精选操作
还有就是返回值,传值返回都是给一个拷贝对象,临时对象/寄存器
也就是无法修改,原因是出于安全的考虑
如果直接传放回对象,那么就是可能还没有运用将这个给销毁
临时对象具有常性,直接就相当于加了一个const
引用做返回值的返回的就改编成为了返回对象的别名
函数销毁之后就是属于把别名给销毁了
这里就是属于属于要返回的是引用的还在不在
引⽤传参跟指针传参功能是类似的,引⽤传参相对更⽅便⼀些。
引⽤和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引⽤跟其他 语⾔的引⽤(如Java)是有很⼤的区别的,除了⽤法,最⼤的点,C++引⽤定义后不能改变指向, Java的引⽤可以改变指向。
(核心就是豹子头林教头林冲,可以通过豹子头得到林教头,在往后,之后的话就是删除林教头,就得不到林冲)
函数重载加引用可以直接 将顺序表当数组用,也就是vector
(编译器就是抽查制度,就是在核心的位置进行一个检查,其他的就是不会去)
还是在说一下,就是返回时一个别名,但是别名空间在值放回之前已经销毁了,
其实就是直接将别名操作,通缉豹子头就是通缉林冲
const引用
给一个const取别名,需要在别名之前也加上const,豹子头不可以干的事林冲可以不干
给一个无const取别名,可以在const上取别名,豹子头可以干的时林冲可以不干
权限不可以放大,可以平移和缩小
原因时因为都是指的同一块空间,正常情况下单赋值时另外申请一块空间
const引用可以用常量
t引用不可以用表达式
这里时权限的放大,表达式的值时需要一个临时空间储存(临时变量或者寄存器),而这里时不允许的,因为这里具有常性
所以要用const引用
同时类型转换也是需要有一个临时的
所以引用的同时需要给一个const
引用和指针的关系
• 语法概念上引⽤是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。
汇编语言也是属于引用和指针时一样的
• 引⽤在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
• 引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象。
• 引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象。
• sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占字节个数(32位平台下 占4个字节,64位下是8byte)
• 指针很容易出现空指针和野指针的问题,引⽤很少出现,引⽤使⽤起来相对更安全⼀些。
inline
用inline对于函数就是内联函数,就是用来代替宏
宏的实现是非常的复杂,这是一种替换机制
#define ADD(a,b)((a)+(b));
分号如果加后面,可以通过
但是如果是流插入的话加;的话不可以
inline的书写
inline int Add(int x, int y)
{
int ret = x + y;
ret += 1;
ret += 1;
ret += 1;
return ret;
}
开始的时候直接进行一个替换,这样的话就是会不用建立栈帧
同时是真不容易出错
仅仅适合用于频繁短小的代码
其实相当于直接给了一个固定空间的函数,之后的话就是call返回
debug是不可以展开,需要调证一下
方式
首先实现汇编,指令是1000行
如果是同样执行1000次,那么宏就是1000*100
而其他的就是1000+100
这样就会让可执行程序,也就是exe变大,所以说inline也就是可以让就是让这个更好用
正常情况就是最多是十几行
不建议在两个文件之中,这样的话展开,没有函数地址,链接时会报错
预处理时候因为有声明,所以说可以过,但是因为链接时候当时头文件以为要用,所以就不会展开,所以说就不会这个样搞。
f.h,f.cpp,test.cpp
预处理:头文件展开,宏替换,去注释,
f.i test.i
接下来就是编译:检查语法,生成汇编代码
f.s tset.s
汇编,生成机器二进制代码
链接 合并到一起,链接只有声明的函数的地址,生成可执行程序
所以说inlin在头文件的时候就是直接第一步就去除了,所以说链接的时候就通过不了,所以说就是不可以,正常情况就是在全部的都放在头文件之中。
而正常情况下的全部的放在头文件中反而有麻烦,因为在汇编是会有符号表对照
这样就是需要加一个static,这样就是只在当前文件可以看见
nullptr
NULL实际是⼀个宏,在传统的C头⽂件(stddef.h)中,可以看到如下代码
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
• C++中NULL可能被定义为字⾯常量0,或者C中被定义为⽆类型指针(void*)的常量。不论采取何种 定义,在使⽤空值的指针时,都不可避免的会遇到⼀些⿇烦,本想通过f(NULL)调⽤指针版本的 f(int*)函数,但是由于NULL被定义成0,调⽤了f(intx),因此与程序的初衷相悖。f((void*)NULL); 调⽤会报错。
• C++11中引⼊nullptr,nullptr是⼀个特殊的关键字,nullptr是⼀种特殊类型的字⾯量,它可以转换 成任意其他类型的指针类型。使⽤nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被 隐式地转换为指针类型,⽽不能被转换为整数类型
#include<iostream>
using namespace std;
void f(int x)
{
cout << "f(int x)" << endl;
}
void f(int* ptr)
{
cout << "f(int* ptr)" << endl;
}
int main()
{
f(0);
// 本想通过f(NULL)调⽤指针版本的f(int*)函数,但是由于NULL被定义成0,调⽤了f(int
x),因此与程序的初衷相悖。
f(NULL);
f((int*)NULL);
// 编译报错:error C2665: “f”: 2 个重载中没有⼀个可以转换所有参数类型
// f((void*)NULL);
f(nullptr);
return 0;
}