1. 命名空间
C++库中的所以的东西都是放在std命名空间中 ,如果将命名空间全部展开,自定义变量不能于std命名空间的变量冲突。
自己也可以创建命名空间,命名空间可以嵌套。
namespace N1
{
int a = 0;
int Add(int left, int right)
{
return left + right;
}
namespace N0 //命名空间可以嵌套
{
int b;
}
}
using namespace N1;
2. cout 和 cin
cout是将数据输出
cout<<i<<j<<endl;
数据i和j通过箭头的方向流向控制台,通过屏幕输出。
cin将数据输入,从控制台获取数据,流向变量。
cout和cin都可以自动识别数据的类型。
3. 缺省传参
缺省参数(默认参数)是一种功能,它允许在声明或定义函数时为函数的参数指定一个默认值。当调用函数而没有提供相应的实参时,将采用这个默认值。
缺省参数-->备胎,如果传了实参,就不用缺省参数
全缺省,半缺省
缺省从右往左缺省 传参从左往右传参
void Funcl(int a = 10, int b = 20, int c = 30)
{
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "c=" << c << endl;
}
半缺省参数必须从右向左依次且连续给出,不能间隔着给。这意味着如果你为一个参数提供了默认值,那么它右边的所有参数也都必须有默认值。
4. 函数重载
函数重载(允许函数名相同),参数不同,(类型/参数的个数/不同类型顺序)其中有一个不同就行 对返回值没有要求(只是返回值不同,不能构成重载)。
4.1 C++是如何支持函数重载的
我们要了解系统编译的过程分为预处理,编译,汇编,链接。
void fun(int n,size_t m)
{
cout << "int" << endl;
}
void fun(char pt)
{
cout << "int*" << endl;
}
void test8()
{
int a = 1;
fun(a,2);
fun('c');
}
主要在链接的时候,重载函数的地址不同。
在经过预处理,编译,汇编之后,两个函数将会变成如下,只有声明。
call fun(?)
call fun(?)
同时会生成符号表
两个函数会到符号表中去找对应的地址,打开反汇编,看看他们地址的区别。
可以看出,在反汇编码中,他们的地址不同,声明了的函数会去找对应的地址。
在linux下,命名规则显而易见了
5. 引用的使用
给一个变量在取一个名字,不会开辟新的空间,一个改变,其他的都改变(在类型后面加&就是引用)(直接在数据前面加&就是取地址)。
5.1 引用的特性:
1.引用必须在定义时初始化
2.已经引用了不能在引用其他数
3.权限的缩小和放大(适用于引用和指针)
void test1()
{
const int a = 1;
//int& b = a; //a是只读,b是可读可写,权限放大 EOF
const int& b = a;
int c = 2;
const int& d = c; //可以,权限缩小
int i = 0;
double db = i;
const double& rd = i;
/// double& rf = i; //此处有隐士类型转换
const double& rf = i;
//对指针
const int* cp = &a;
// int* p1 = cp; //权限放大
const int* p2 = cp;
}
5.2 隐式类型的转换
int Add_(int r1,int r2)
{
return r1 + r2;
}
int& Add1(int r1, int r2)
{
int c = r1 + r2;
return c;
}
int& Add2(int r1,int r2)
{
static int c = r1 + r2;
return c;
}
void test3()
{
int a = 2;
int b = 3;
const int& ret = Add_(a, b); //返回的数据是将r1+r2和拷贝的数据,是一个临时变量,具有常性,引用时要用const
cout << ret << endl;
int& ret1=Add1(a,b);
Add1(3, 4);
cout << ret1 << endl; // ret1 是7 ,因为c的生命周期只在Add1函数中,结束后销毁,而ret1又是c的别称,指向的是c的空间,该处内存的数据被覆盖(如果ret仅接收c的值,而非别称,就没事)
int& ret2 = Add2(a, b);
Add2(3, 4);
cout << ret2 << endl; // 用static 改变了c的生命周期
}
一般用值返回用别名(引用)接收时, 应该加const (例:const int& b = Add(a,b) int Add(int x ,int y); 因为返回的是对返回数据的拷贝(是临时变量,具有常性,不能修改)。
5.3 指针与引用的区别
1.引用概念上定义一个变量的别名,指针存储一个变量地址。
2.引用在定义时必须初始化,指针没有要求
3.引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体
4.没有 NULL 引用,但有 NULL 指针
5.在 sizeof 中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)
6.引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
7.有多级指针,但是没有多级引用
8.访问实体方式不同,指针需要显式解引用,引用编译器自己处理
9.引用比指针使用起来相对更安全
6. auto
作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto 的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译 期会将auto替换为变量实际的类型。
auto不能推导的场景
1. auto不能作为函数的参数
2. auto不能直接用来声明数组
7. 范围for
与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环.
for循环迭代的范围必须是确定的
对于数组而言 就是数组中第一个元素和最后一个元素的范围。
对于类而言, 应该提供begin和end的方法,begin和end就是for循环迭代的范围。(获取begin和end的迭代器,对迭代器解引用,如果是自定义的类,需要自己写函数实现)(不停的对begin()返回值做加法,解引用,直到遇到end())。
8.C++中的NULL和nullptr
NULL可能被定义为常量 0,也可能定义为void*类型
用nullptr代替NULL更具有安全性
void fun(int n)
{
cout << "int" << endl;
}
void fun(int* n)
{
cout << "int*" << endl;
}
void test8()
{
fun(NULL);
fun(nullptr);
}
结果:NULL被判定为int 类型