★★★★★ 互相学习,共同进步!
目录
3、使用(三种使用方法,在此举例时共同使用方法一的命名空间)
一、命名空间
1、引出
在C/C++中我们不免的会定义一些变量、函数、类型等,且其通常定义在我们的全局域当中,这样我们一旦定义了一个变量名和函数库中的函数重命名且作用域相同时,就会发生错误。例如下面的代码运行就会报错。
#include<stdio.h>
#include<stdlib.h>
int rand = 0;
int main()
{
printf("%d\n", rand);
return 0;
}
报错原因:我们在全局定义的变量rand和库函数重名且在编译器中的作用域相同,所以会报错。试想一下,当我们在编写大型项目时很有可能会出现大量重命名的问题,那么为了避免这样的问题,提出了命名空间的用法。
2、介绍
命名空间是将我们定义的变量、函数等与库函数加以分隔起来,相当于在不同的域中,避免由于重命名问题而引发冲突。
namespace space
{
int rand = 10;
int add(int x, int y)
{
return x + y;
}
struct Node
{
int val;
struct Node* next;
};
namespace nice
{
int c = 20;
char s = 'x';
};
};
上面代码中的namespace是命名空间的关键字,声明命名空间时必须包含;后面space时命名空间的名字,可以任意选择。命名空间中的成员可以定义为变量、函数、类型,同时还可以嵌套命名空间。
注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。
3、使用(三种使用方法,在此举例时共同使用方法一的命名空间)
方法一:命名空间名称及作用域限定符
namespace space
{
int rand = 10;
int add(int x, int y)
{
return x + y;
}
struct Node
{
int val;
struct Node* next;
};
namespace nice
{
int c = 20;
char s = 'x';
};
};
int main()
{
printf("%d\n", space::rand);
printf("%d\n", space::add(3, 10));
printf("%d\n", space::nice::c);
return 0;
}
方法二:使用using将命名空间中成员引入
using space::add;
int main()
{
printf("%d\n", add(3, 7));
return 0;
}
方法三:使用using namespace 命名空间名称引入
using namespace space;
int main()
{
printf("%d\n", add(3, 10));
printf("%d\n", nice::c);
return 0;
}
二、C++的输入/输出
#include<iostream>
using namespace std;
int main()
{
int i = 10;
double j = 23.11;
char name[10];
cout << i << ' ' << j << endl;
cout << "hello world!" << endl;
cin >> name;
cout << name << endl;
return 0;
}
说明:
1、使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空间。2、std可以看作是一个定义了库函数的命名空间。(包含cout等)
3、cout(printf) << 流插入运算符,cin(scanf) >> 流提取运算符,endl 表示换行('\n')
4、使用C++输入输出更方便,不需增加数据格式控制,比如:整形--%d,字符--%c
三、缺省参数
1、概念
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
void TestFunc(int a = 10)
{
cout << a << endl;
}
int main()
{
TestFunc(); // 没有传参时,使用参数的默认值
TestFunc(100); // 传参时,使用指定的实参
return 0;
}
2、缺省参数的分类
★全缺省参数
void TestFunc(int a = 10, int b = 20, int c = 30)
{
cout<< a <<endl;
cout<< b <<endl;
cout<< c <<endl;
}
int main()
{
TestFunc(); // 没有传参时,使用参数的默认值
return 0;
}
★半缺省参数
void TestFunc(int a, int b = 10, int c = 20)
{
cout<< a <<endl;
cout<< b <<endl;
cout<< c <<endl;
}
int main()
{
TestFunc(30); // 没有默认值的参数必须传参
TestFunc(30,300); // 有默认值的参数,使用时可传参也可不传参
return 0;
}
注意:
1. 半缺省参数必须从右往左依次来给出,不能间隔着给
2. 缺省参数不能在函数声明和定义中同时出现 3. 缺省值必须是常量或者全局变量
四、函数重载
1、概念(C++支持函数重载,C不支持)
函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数 个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。
int Add(int a, int b)
{
return a + b;
}
int Add(char a, char b)
{
return a + b;
}
int Add(int a, char b)
{
return a + b;
}
int Add(char a, int b)
{
return a + b;
}
int main()
{
cout << Add(3, 7) << endl; // 10
cout << Add('a', 'b') << endl; // 195
cout << Add(3, 'a') << endl; // 100
cout << Add('a', 7) << endl; // 104
return 0;
}
五、引用
1、概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
int main()
{
int a = 10;
int& b = a; // 引用,类型& 引用变量名(对象名) = 引用实体
cout << a << endl;
cout << b << endl;
return 0;
}
注意:引用类型必须和引用实体是同种类型的
2、引用特性
1)引用在定义时必须初始化
2)一个变量可以有多个引用 3)引用一旦引用一个实体,再不能引用其他实体
int main()
{
int a = 10;
int ra = 100;
int& b = a; // 引用
int& c = a;
int& d = a;
//int% b = ra; // 引用一旦引用一个实体,再不能引用其他实体
cout << a << endl;
cout << b << endl;
cout << c << endl;
cout << d << endl;
return 0;
}
3、常引用
void TestFunc()
{
const int a = 10; // 只读
// 权限放大(只读 --> 可读可写)
//int& ra = a; // 该语句编译时会出错,a为常量
// 权限不变
const int& ra = a;
// 权限缩小()
int b = 10;
const int& rb = 10;
double d = 12.34;
//int& rd = d;
const int& rd = d; // 保留整数部分
cout << a << endl;
cout << ra << endl;
cout << b << endl;
cout << rb << endl;
cout << d << endl;
cout << rd << endl;
}
int main()
{
TestFunc();
return 0;
}
4、使用场景
1)做参数
int Add(int& a, int& b)
{
return a + b;
}
int main()
{
int a = 4;
int b = 6;
cout << Add(a, b) << endl;
return 0;
}
2)做返回值
正确示例:
int& Count()
{
static int n = 0;
n++;
return n;
}
int main()
{
int& a = Count();
cout << a << endl;
return 0;
}
返回类型为引用类型,static修饰的变量n存储在静态区,当调用函数Count栈帧销毁后,n仍存在,不随着栈帧销毁,所以值不会发生变化。
错误示例:
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& x = Add(300, 500);
cout << x << endl;
return 0;
}
从上述代码的输出结果我们可能没有发现问题,但是事实上,函数返回的时Add函数中局部变量c的引用,当函数调用完成后栈帧销毁,再次引用访问属于非法访问。
注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。
5、引用和指针的区别
★ 在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
★ 在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
int main()
{
int a = 10;
cout << a << endl; // 10
int& ra = a;
ra = 20;
cout << ra << endl; // 20
int* pa = &a;
*pa = 30;
cout << a << endl; // 30
return 0;
}
引用和指针的不同点:
1. 引用在定义时必须初始化,指针没有要求
2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
3. 没有NULL引用,但有NULL指针
4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
6. 有多级指针,但是没有多级引用
7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
8. 引用比指针使用起来相对更安全
六、auto关键字(C++)
1、介绍
C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
int TestAuto()
{
return 10;
}
int main()
{
int a = 10;
auto b = a;
auto c = 'a';
auto d = TestAuto();
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
//auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
return 0;
}
注意:
使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型
2、auto使用细则
1)auto与指针和引用结合起来使用
用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
int main()
{
int a = 10;
auto b = a;
char c = 'a';
auto d = c;
auto& e = a;
cout << typeid(b).name() << endl;
cout << typeid(d).name() << endl;
cout << typeid(e).name() << endl;
return 0;
}
2)在同一行定义多个变量
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编 译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
int main()
{
auto a = 1, b = 2, c = 3;
//auto x = 10, y = 10.23; // 类型不同,会报错
cout << typeid(a).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
return 0;
}
3、auto不能推导的场景
1)auto不能作为函数的参数
2)auto不能直接用来声明数组
3)为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
七、基于范围的for循环
1、不包含auto对for的使用(普通遍历)
void Test()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int n = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < n; i++)
{
arr[i] += 1;
}
for (int i = 0; i < n; i++)
{
cout << arr[i] << endl;
}
}
2、包含auto对for的使用
void Test()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int n = sizeof(arr) / sizeof(arr[0]);
for (auto& e : arr)
{
e += 1;
}
for (auto e : arr)
{
cout << e << endl;
}
}
这里for循环中,e变量代表所给范围成员,arr即遍历范围;第一个循环当中需要改变遍历过程中的元素,所以使用了引用。
3、范围for的使用条件
1) for循环迭代的范围必须是确定的 对于数组而言,就是数组中第一个元素和最后一个元素的范围
2)迭代的对象要实现++和==的操作。
★★★★★ 互相学习,共同进步!
★★★★★ 感谢您的阅读!