文章目录
1.C++关键字
C++总计63个关键字,C语言32个关键字
ps:下面我们只是看一下C++有多少关键字,不对关键字进行具体的讲解。后面我们学到以后再细讲。
asm | do | if | return | try | continue |
---|---|---|---|---|---|
auto | double | inline | short | typedef | for |
bool | dynamic_cast | int | signed | typeid | public |
break | else | long | sizeof | typename | throw |
case | enum | mutable | static | union | wchar_t |
catch | explicit | namespace | static_cast | unsigned | default |
char | export | new | struct | using | friend |
class | extern | operator | switch | virtual | register |
const | false | private | template | void | true |
const_cast | float | protected | this | volatile | while |
delete | goto | reinterpret_cast |
2.命名空间
为什么存在
为了解决命名冲突
#include<stdio.h> #include<stdlib.h>//里面包含rand函数 int rand = 0;//全局变量rand int main() { printf("rand = %d\n", rand);//编译器不知道打印的是函数的地址(函数名 == 函数的地址)还是全局变量rand的值 printf("%d\n",rand());//这样没问题,这样相当于是调用rnad函数 return 0; }
但是写成这样没问题
#include<stdio.h> #include<stdlib.h> int main() { int rand = 0;//此时的rand变量为局部变量,局部优先, printf("rand = %d\n", rand);//0 局部优先,打印的是局部变量rand的值 return 0; }
若rand为全局变量则有问题了,因为rand函数和rand变量都是全局变量,编译器不知道哪个是你要打印的是哪个
但是若rand为局部变量就没有问题,全局变量和局部变量可以同名,使用时原则为:局部优先(先使用局部变量
编译器寻找变量的规则是:先在该作用域中寻找该局部变量,找不到再去全局变量中找,如果还是找不到,就会报错
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
- 使用命名空间后
#include<stdio.h>
#include<stdlib.h>
namespace M_Space//定义一个叫M_Space的命名空间-域
{
int rand = 0;
}
int a = 10;
int main()
{
printf("rand = %d\n", rand);
// :: 域作用限定符
printf("命名空间的rand = %d\n", M_Space::rand);//表示rand再M_Space这个域中寻找
M_Space::rand = 10;
printf("修改值后:命名空间的rand = %d\n", M_Space::rand);
printf("%d\n" , ::a);//10
//若域作用限定符的坐标是空白,则说明再全局域中寻找
return 0;
}
命名空间的定义
命名空间是全局的,命名空间里面的成员也是全局的变量
定义命名空间,需要使用到
namespace关键字
,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。
- 例子
namespace MS //MS是命名空间的名字 - 域
{
int a = 0;//a是全局变量,放在静态区,是MS命名空间的成员,
}
域中的成员变量是不能在域中赋值的!只能初始化时候赋初始值
命名空间中的内容,既可以定义变量,也可以定义函数,也可以创建类型(结构体,联合体…)
namespace M_Space
{
int a = 0;
int Add(int x, int y)
{
return x +y ;
}
struct Student
{
int age;
char sex[7];
};
}
- 命名空间中的结构体使用时的注意事项
namespace M_Space
{
struct Student
{
int age;
char sex[7];
};
}
M_Space::struct Student stu;//err
struct M_Space::Student stu;//写法1
M_Space::Student stu;//写法2
写法1-> 域要加载结构体名字前,不能放在struct前
写法2-》也可以省略struct不写
- 命名空间内部的变量可以定义时初始化,但是不可以再次在命名空间内再次赋值,要再次赋值要在其它函数内赋值
namespace M_Space
{
int a = 0;//定义时初始化
int b;//只定义不初始化
a = 10;//err
b = 5;//err
}
M_Space::a = 10;//err 在外部赋值也不可以,要在函数内部赋值
void test()
{
M_Space :: a = 10;//可以
}
原因分析:
命名空间内创建的是全局变量,全局变量要在函数内部赋值,初始化时只能赋初始值
int a = 10; a = 20;//err int main() { a = 10;//OK return 0; }
2.命名空间可以嵌套
namespace N1
{
int a = 2;
namespace N2
{
int b = 3;
}
}
int main()
{
N1::a = 2;
N1::N2::b = 1;
//同样也是使用::域作用限定符进行逐层访问
printf("a = %d b = %d\n", N1::a, N1::N2::b);// 2 1
return 0;
}
3.同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
namespace N1
{
int a = 0;
int b = 2;
}
namespace N1
{
int a = 1;
}
int main()
{
printf("a = %d b = %d\n", N1::a, N1::b);
return 0;
}
相同名称的命名空间,最后会合成同一个命名空间中,所以相同名称的命名空间里面的成员名字不能相同,否则会报错
命名空间不影响变量的属性,它还是全局变量。只是影响了编译器找该变量的规则
命名空间里面可以只放声明(函数声明)
命名空间的使用
方法1:加命名空间名称及作用域限定符 ::
命名空间名称 :: 成员名;
namespace M1
{
int a = 10;
}
int main()
{
printf("before:M1::a = %d\n", M1::a);//10
M1::a = 20;
printf("after:M1::a = %d\n", M1::a);//20
return 0;
}
优缺点:
- 优点:不会造成命名污染
- 缺点:使用麻烦
方法2:使用using将命名空间中成员引入
using 命名空间名称 :: 要展开的成员;
namespace M1
{
int a = 10;
int b = 20;
}
//单独展开M1中的a变量,其它不展开
using M1::a;
int main()
{
printf("a = %d\n", a);//10
printf("b = %d\n", b);//b未被引入,编译器找不到,会报错
return 0;
}
想要程序没问题:把b也展开
using M1::a;
using M1::b;
方法3:使用using namespace命名空间名称引入
using namespace 命名空间名称 ;
这种写法是直接把整个命名空间展开,使用方便,但是命名空间的隔离作用就失效了
namespace M1
{
int a = 10;
int b = 20;
}
//把M1这个命名空间展开-展开到全局
using namespace M1;
int main()
{
printf("a = %d\n", a);//10
printf("b = %d\n", b);//20
return 0;
}
namespace N1
{
int a = 2;
namespace N2
{
int a = 3;
}
}
using namespace N1;
int a = 0;
int main()
{
//printf("a = %d ", a);//err,未知要打印的是N1的成员变量a还是外部的全局变量a
printf("a = %d ", N1::a);//这样使用了域限定符就可以
return 0;
}
命名空间N1展开之后,N1里面的全局变量a和外部的全局变量a重名了。
N1失去了隔离作用
优缺点:
- 优点: 使用成员方便
- 缺点:由于是展开到全局,如果全局也有相同名字变量或函数名等,会造成命名污染,编译器报错
3.C++的输入输出
1.使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空
间。
注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件
即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文 件不带.h
;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用
推荐使用的版本
#include<iostream>//input ouput stream 输入输入流 C++输入输出头文件
using namespace std;//C++库的实现定义在一个叫std的命名空间中
//这样写 ==>把std这个命名空间的内容展开到全局
老版本
#include<iostream.h> // VC6.0 -> 比较老版本的库,没有命名空间的
2.使用C++输入输出更方便,不需增加数据格式控制,比如:整形–%d,字符–%c
c语言中使用
scanf 和 printf
进行输入输出,而C++也有输入输出,那就是cin 和 cout
,其中cin是输入,搭配>>
使用;cout是输出,搭配<<使用.
输出 cout
搭配 << 流插入运算符
#include<iostream>
//std命名空间的内容全局展开
using namespace std;
int main()
{
cout << "Hello world\n" ;
cout << "Hello world" << endl;//endl ->相当于\n
cout << "Hello" << " " << "world" << endl;
return 0;
}
#include<iostream>
//只展开std命名空间里面的cout和endl成员
using std::cout;
using std::endl;
int main()
{
int a = 0;
double d = 3.14;
//自动识别变量的类型
cout << "a = " << a << " d = " << d<< endl;
return 0;
}
cout打印的默认就是你写的,不会把小数后面的也打印出来
int main()
{
double d = 3.14;
cout << "d = " << endl;
return 0;
}
输入 cin
搭配 >> 流提取运算符
cin也不可读取空格,会自动忽略 和scanf类似
#include<iostream>
//std命名空间的内容展开到全局
using namespace std;
int main()
{
int a = 0;
double b = 0;
//自动识别类型
cin >> a;
cin >> b;
printf("a = %d b = %.2lf\n", a, b);
return 0;
}
#include<iostream>
//只展开std命名空间里面的cin成员
using std::cin;
int main()
{
int a = 0;
double b = 0;
cin >> a;
cin >> b;
printf("a = %d b = %lf\n", a, b);
return 0;
}
4.缺省参数
概念
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
缺省参数的例子
void Test(int a = 0)
{
cout<<"a = "<< a <<endl;
}
int main()
{
Test();//没有传参时,使用参数的默认值
Test(1);//传参时,使用指定的实参
return 0;
}
全缺省参数
所以参数都给了缺省值
void func(int x = 0, int y = 1)
{
cout << "x = " << x << endl;
cout << "y = " << y << endl;
cout << endl;
}
int main()
{
func();
func(3);
func(3, 4);
//func( ,4)//只给y赋值,x取默认值,err
//不能在调用的时候指定传给谁
}
半缺省参数
缺省部分参数,并且默认值必须从右往左依次给出
void func(int x, int y = 0)
{
cout << "x = " << x << endl;
cout << "y = " << y << endl;
cout << endl;
}
int main()
{
func(1);
func(1,2);
//func();//err
}
半缺省参数必须从右往左依次来给出,不能间隔着给
即:必须从右往左缺省,必须连续的缺省,不能跳着缺省
void func(int x = 0,int y,int z = 1) //err
{}
void func(int x,int y = 0,int z) //err
{}
void func(int x,int y ,int z = 0) //OK
{}
缺省参数不能在函数声明和定义中同时出现
//func.cpp中
void func(int x, int y = 0)
{}
//func.h中
void func(int x, int y = 0);
->报错
这里是引用
原因:
如果声明与定义函数的位置同时出现缺省参数,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值。
如:
//func.cpp中
void func(int x, int y = 0)
{}
//func.h中
void func(int x, int y = 2);
解决办法:要么在声明中写缺省参数,要么在定义中写缺省参数。推荐写在:声明,因为查看代码的时候一般先看它的声明
//func.cpp中
void func(int x, int y)
{
cout << "x = " << x << endl;
cout << "y = " << y << endl;
cout << endl;
}
//func.h中-写在声明里面
void func(int x, int y = 2);
int main()
{
func(1);
func(3,4);
return 0;
}
缺省值必须是常量或者全局变量
//缺省值为全局变量
int c = 0;
void func(int x,int y = c)
{}
//缺省值为常量
void func(int x,int y = 1)
{}
- 总结
1.半缺省参数必须从右往左依次来给出,不能间隔着给
2.缺省参数不能在函数声明和定义中同时出现
3.缺省值必须是常量或者全局变量
4.C语言不支持(编译器不支持)
使用缺省参数的好处(例子)
struct Stack
{
int* a ;
int capacity;
int size;
}
//使用缺省参数
void StackInit(struct Stack* ps,int capacity = 4)
{
ps- > a = (int*)malloc(sizeof(int)*capacity);
ps -> size = 0;
ps -> capacity = capacity;
}
int main()
{
struct Stack st;
//StackInit(&st);//不知道栈最多存多少数据,就用缺省参数初始化
StackInit(&st,100);//知道栈最多存100个数据,用显示传值,这样可以减少增容次数,提高效率
}
增容是有代价的:realloc ():若后面空间不够,要重新开辟空间,把原空间数据拷贝过去,然后释放原空间
缺省参数函数相比于普通的函数调用时更灵活,比如在栈的初始化时可以通过传入指定的参数开辟对应大小的内存空间,如果不指定参数则开辟默认大小