1、命名空间的作用就是为了对标识符进行隔离,避免相同的名字产生冲突
namespace N1//N1是命名空间的名称
{
//命名空间的内容既可定义变量也可定义函数
int a = 2;
int ADD(int x, int y)
{
return x + y;
}
}
namespace N2
{
int a = 3;
int b = 5;
int ADD(int x, int y)
{
return x + y;
}
namespace N3 //命名空间可嵌套使用
{
int a = 5;
int b = 7;
void Swap(int *pa, int *pb)
{
int tmp = *pa;
*pa = *pb;
*pb = tmp;
}
}
}
注:一个命名空间就定义了一个新的作用域,命名空间中所有内容都只局限于该命名空间
2、命名空间使用
(1)加命名空间名称和作用域限定符::
int main()
{
int a = 3;
int b = 4;
printf("%d\n", N1::a);//输出2,输出的是命名空间N1中的a
printf("%d\n", N2::a);//输出3,输出的是命名空间N2中的a
printf("%d\n", N2::N3::a);//输出5,输出的是命名空间N3中的a
N1::ADD(2, 3);
N2::N3::Swap(&a, &b);
return 0;
}
(2)使用using将命名空间中的成员引入
using N1::ADD;
int main()
{
int c = ADD(3, 4);
printf("%d\n", c);
return 0;
}
(3)使用using namespace 将命名空间引入
using namespace N2;
int main()
{
printf("%d\n", a);//输出N2中a的值3
return 0;
}
#include
//using namespace std;
using std::cout;
using std::cin;
using std::endl;//换行
int main()
{
int a;
double b;
cin >> a >> b;//从键盘中输入a = 2,b = 3.14
cout << a << endl;//输出到控制台a,b的值
cout << b << endl;
return 0;
}
在声明或是定义函数时为函数的参数指定一个默认值,在调用函数时若是没有传参则采用该默认值,否则使用实参
#include
using namespace std;
//全缺省参数
void Test(int a = 10, int b = 20, int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
半缺省参数,调用该函数时必须给a传参
注:1、半缺省参数必须从右往左依次缺省,不能间隔着给
注:2、缺省参数不能在函数定义和声明中同时出现,若同时出现且缺省值不同,系统无法判断使用哪一个
void Test1(int a, int b = 20, int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main()
{
Test();//输出10,20,30
Test(1);//输出1,20,30
Test(1,2);//输出1,2,30
Test(1,2,3);//输出1,2,3
Test1(1);
Test1(1,2);
Test1(1,2,3);
return 0;
}
5.1、在同一个作用域中声明几个功能类似的同名函数,这些函数的形参列表(参数个数 或 类型 或 顺序)必须不同
#include
using namespace std;
int ADD(int x, int y)
{
return x + y;
}
double ADD(double x, double y)
{
return x + y;
}
int main()
{
int c = ADD(3, 4);
double d = ADD(3.14, 2.34);
cout << c << endl << d << endl;
return 0;
}
5.2、程序运行需经历的过程
5.3、名字修饰(name Mangling),指在编译过程,将函数、变量的名称重新改编,生成全局中唯一的名称,便以区分各个函数和变量
5.4、为了支持C语言调用C++模块中用C语言规则写的函数,于是在函数前加extern “C”,告诉编译器将该函数按照C语言规则来编译
extern "C" int Add(int x, int y)
{
return x + y;
}
int main()
{
ADD(3, 4);
return 0;
}
6.1、引用的定义
类型& 引用变量名(对象名) = 引用实体
#include
using namespace std;
void TestRef()
{
int a = 10;
int& b = a;//定义引用类型,引用类型必须和引用实体是一个类型的
printf("%p\n", a);//0000000A
printf("%p\n", b);//0000000A
}
int main()
{
TestRef();
return 0;
}
6.2 引用特性
6.3 常引用
void TestConstRef()
{
const int a = 10;
//int& b = a; 此声明引用类型是错误的
const int& b = a;
double c = 3.14;
double& d = c;
const int& e = c;//此类声明可行,因为在类型转换时中间会产生临时变量,
//该临时变量是不可改变的常量,此时引用必须加上const
}
6.4 使用场景
1、做参数
void Swap(int& x, int& y)//此时参数x,y是分别实参a,b的别名,x和a表示的是同一个内存空间,y和b表示的是同一个内存空间交换x,y即交换a,b
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 10;
int b = 20;
Swap(a, b);
return 0;
}
2、做返回值
int TestReturn(int a)
{
a += 10;
return a;
//此时不会用a返回,因为a是局部变量,出了TestReturn函数之后就会被销毁,
其栈上的空间也会还给系统,因此不能用栈上的空间作为返回值返回a的值是在执行
TestReturn函数时就在main函数的栈帧中为a创建一个临时空间存储a的值,
TestReturn函数执行完后,再将临时空间中的值赋值给y
}
//使用引用做参数,返回值得生命周期不受函数的限制
int& TestReturn1(int& a)
{
a += 20;
return a;
}
int main()
{
int x = 10;
int y = TestReturn(x);
return 0;
}
6.5 传值、传引用、传指针的效率比较
传值效率最低,因为需要开辟临时空间,才能接受所传递的值
传引用、传指针效率几乎相同,都不需要重新开辟空间
6.6 引用和指针的区别
7.1 内联函数的定义
1、使用时编译器会把inline标注的函数在调用内联函数处展开,没有函数压栈开销,是以空间换时间的做法但是代码很长或者有循环/递归的函数不适合做内联函数
2、inline对于编译器只是一个建议,编译器会自动优化,如果内联函数代码很长或者有循环/递归,编译器优化时会忽略内联函数
3、inline不建议声明与定义分离,会导致链接错误,因为在展开inline函数时找不到函数体,没有函数地址,链接找不到
宏函数
ADD的宏函数
#define int ADD(int a,int b) return a+b
#define ADD(a,b) a+b
#define ADD(a,b) ((a)+(b))
//Swap的宏函数
#define Swap(x,y)\
(x) = (x)+(y); \
(y) = (x)-(y); \
(x) = (x)-(y)
int main()
{
int c = ADD(2, 3);//预处理时替换为 int c = ((2)+(3));
int d = ADD(2 + 3, 4) * 3;// 预处理时替换为 int d = ((2+3)+(4))*3;
Swap(c, d);
cout << c << endl;
cout << d << endl;
return 0;
}
int TestAuto()
{
return 10;
}
int main()
{
int a = 10;
auto b = a;
auto c = 'a';
auto d = TestAuto();
//auto e;无法通过编译,使用auto定义变量时必须初始化
cout << typeid(b).name() << endl;//int
cout << typeid(c).name() << endl;//char
cout << typeid(d).name() << endl;//int
return 0;
}
8.1 auto的使用细则
(1)auto与指针和引用结合起来使用
int main()
{
int x = 10;
auto a = &x;
auto* b = &x;
auto& c = x;
cout << typeid(a).name() << endl;//int*
cout << typeid(b).name() << endl;//int*
cout << typeid(c).name() << endl;//int
*a = 20;
*b = 30;
c = 40;
return 0;
}
(2)在同一行定义多个变量,变量类型必须是相同的类型,否则编译器会报错,
因为编译器只对第一个变量的类型进行推导,然后用推导出来的类型定义其他变量
void TestAuto()
{
auto a = 1, b = 2;
auto c = 3, d = 4.0;//编译失败,因为c和d初始化的表达式类型不同
}
8.3 auto不能推导的场景
(1)不能作为函数的参数,因为函数只有在被调用时才会接收到
void TestAuto(auto a)
{}
值,在此之前编译器无法对a的实际类型进行推导
(2)auto不能直接声明数组
void TestAuto()
{
int a[] = { 1, 2, 3 };
auto b[3] = a;
}
9.1范围for的语法
void TestFor1()
{
int array[] = { 1, 2, 3, 4, 5, 6 };
for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
{
array[i] *= 2;
}
for (int i = 0; i < sizeof(array)/sizeof(int); ++i)
{
printf("%d ", array[i]);
}
}
void TestFor2()
{
int array[] = { 1, 2, 3, 4, 5, 6 };
for (auto& e : array)
e *= 2;
for (auto& e : array)
cout << e << " ";
}
int main()
{
TestFor1();
TestFor2();
return 0;
}
9.2 范围for的使用条件:for循环的迭代范围必须是确定的
void TestFor(int array[])
{
for (auto& e : array)//for循环范围不确定
cout << e << " ";
}
10.1 表示指针指向空时相当于 *ptr = NULL,nullptr的类型是nullptr_t