命名空间定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。 如namespace N1{ … …}
1.命名空间中的内容,既可以定义变量,也可以定义函数
2.命名空间可以嵌套
3.同一个工程中允许存在多个相同名称的命名空间编译器最后会合成同一个命名
空间中。
命名空间的使用有三种方式:
1.加命名空间名称及作用域限定符
int main()
{
printf("%d\n", N::a);
return 0;
}
2.使用using将命名空间中成员引入
using N::b;
int main()
{
printf("%d\n", N::a);
printf("%d\n", b);
return 0;
}
3.使用using namespace 命名空间名称引入(不建议使用)
using namespce N;
int main()
{
printf("%d\n", N::a);
printf("%d\n", b);
Add(10, 20);
return 0;
缺省参数概念
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该
默认值,否则使用指定的实参。
void TestFunc(int a = 0) {
cout<<a<<endl; }
int main()
{
TestFunc(); // 没有传参时,使用参数的默认值
TestFunc(10); // 传参时,使用指定实参
- 半缺省参数必须从右往左依次来给出,不能间隔着给
. 如void Fun(int a = 0,int b ,int c)
正确
void Fun(int a,int b = 1,int c = 2)
不正确(因为从右往左c和b缺省可a却不缺省) - 缺省参数不能在函数声明和定义中同时出现
//a.h
void TestFunc(int a = 10);
// a.c
void TestFunc(int a = 20)
{}
// 注意:如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个
缺省值。
3. 缺省值必须是常量或者全局变量
函数重载
参数的个数、参数的类型、参数的顺序 不同(函数的返回类型不同也不可以)(在同一个作用域下)(也就是如果一个ADD函数在全局,一个在命名空间里,这并没有构成重载,用命名空间的ADD必须加域名)。
为什么C++可以重载而C语言却不可以?
··C语言:不支持重载 --> 函数名修饰规则不支持 --> _ + 函数名 --> 相同的函数名无法区分
·· C++: 支持重载 --> 函数名修饰规则支持 --> 前缀 + 函数名 + 参数信息 --> 相同的函数名可以区分
extern “c” { ··· ···} 按c语言风格来编译
引用
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,再不能引用其他实体(类似于int* const a)
··引用:char& a = b
相当于 char* const a
底层实现上,引用通过指针实现(int*a 和 int&a 的汇编代码是一样的)
引用: a++ --> a = 2
指针:++ 是加地址
sizeof(a) = sizeof(char) 就看引用是什么类型
常引用
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; }
引用和指针的区别
- 引用在定义时必须初始化,指针没有要求
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型
实体 - 没有NULL引用,但有NULL指针
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占
4个字节) - 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但是没有多级引用
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 引用比指针使用起来相对更安全
- 函数传引用比传指针更快
内联函数:
·· 1.inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜
使用作为内联函数。
2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等
等,编译器优化时会忽略掉内联。
3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
4. 类似宏替换,但是宏替换没有语法检查,传参的检查,相对不安全
宏的优缺点?
优点:
1.增强代码的复用性。
2.提高性能。
缺点:
1.不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型安全的检查 。
C++有哪些技术替代宏?
- 常量定义 换用const
- 函数定义 换用内联函数
auto
·· auto 定义变量,必须初始化,变量的实际类型由初始化表达式确定
其中auto p = &a == auto* p = &a
而引用必须 auto& p = a; 不能auto p = a;
·· auto 不能作为函数的参数,不能直接用来声明数组
可以auto a = 1,b = 2. 但是a和b 的类型必须一致,auto是按照 定义的第一个变量来确定类型
. 基于范围的for循环
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中
引入了基于范围的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来跳出整个循环。
范围for的使用条件
for循环迭代的范围必须是确定的
对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的
方法,begin和end就是for循环迭代的范围。
注意:以下代码就有问题,因为for的范围不确定
void TestFor(int array[])
{
for(auto& e : array)
cout<< e <<endl; }
指针空值nullptr
- 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
- 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
- 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。
·· C语言中 NULL 本质上是宏替换 NULL == 0 , 也就是fun(int* a) 和 fun(int a) 调用时用fun(NULL)调用的是int 的,想调用int* 的就直接用fun((int*) NULL)
int* p = NULL == int* p = 0;
··C++中 fun(nullptr) 调用的是 fun(int* a)