目录
1.4.4 方式3:使用using namespace 命名空间名称 引入
一、命名空间(namespace)
在我们之前写C语言的时候,可能会写许多的变量、函数和类,这些变量、函数和类的名称很有可能会相同,从而导致一些冲突。为此C++提供了一种避免命名冲突和隔离不同模块的标识符的方式,即命名空间。
1.1 命名空间的概念
命名空间(namespace)是一种用于组织和管理代码标识符(如变量、函数、类等)的机制。
它通过将相关的代码实体放置在特定的命名空间中,可以将这些实体进行分类和分组,并确保它们不会与其他命名空间中的实体发生冲突。
#include <stdio.h>
#include <time.h>
int time = 10;
int main()
{
printf("%d\n", time);
return 0;
}
// 编译后后报错:error C2365: “time”: 重定义;以前的定义是“函数”
上面在全局作用域中定义了int型的time,但是time在time.h库函数中已经被定义:
time_t time(time_t *seconds)
于是编译后报错:error C2365: “time”: 重定义;以前的定义是“函数”
C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
1.2 命名空间的定义
定义命名空间的格式如下:
namespace n1
{
//...
}
namespace是关键字 n1是命名空间的名字 {}中的是命名空间的成员
1.3 命名空间的特征
- 1. 在命名空间内部,可以包含变量、函数、类等。
例如:
( 注:需要使用C++,文件后缀为 .cpp)namespace n1 { double time = 10.16; void Func() { printf("void Func()\n"); // 函数实现 } struct Node { struct Node* next; int val; }; }
- 2. 命名空间可以嵌套(命名空间内部也可以包含命名空间)
namespace n1 { double time = 10.16; namespace n2 { //double time = 10.21; int a = 1; int b = 1; int c = 1; int Add(int a, int b) { return a + b; } //... } }
- 3. 同一个工程中允许存在多个同名的命名空间,编译器最后(链接)会合成为同一个命名空间
//test1.cpp namespace n1 { int a = 1; void Func1() { // 函数实现 } } //test2.cpp namespace n1 { int b = 2; void Func2() { // 函数实现 } }
-
注:以下情况报错
1、多个同名命名空间中有相同名称的成员
2、一个命名空间中有两个相同名称的成员 -
总结:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
1.4 命名空间使用
1.4.1 作用域解析运算符 ::
使用命名空间中的代码实体时,可以通过使用作用域解析运算符 :: 来指定所属的命名空间。
//作用域解析运算符 :: 左边是命名空间名
//右边是命名空间中的成员
1.4.2 方式1:加命名空间名称及作用域限定符
例如,若是在上述示例中引用命名空间n1中的变量和函数:
//一定要在.cpp文件
#include <iostream>//C++的标准库
using namespace std;
//std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
//使用方法看下面的方式3
int main()
{
printf("%.2f\n",n1::time);
//作用域解析运算符 :: 左边是命名空间名
//右边是命名空间中的成员
Func();
return 0;
}
特点: 指定访问、安全性高、经常使用会麻烦
1.4.3 方式2:使用using将命名空间中某个成员引入
#include <iostream>
using namespace std;
//using n1::time;
using n1::Func
int main()
{
//printf("%.2f\n", time);
//报错,因为std中包含了time函数,必须要指定作用域
printf("%.2f\n", n1::time);
//main函数前不能写using n1::time;会和std的冲突
//error C2874: using 声明导致多次声明“<未知>
Func();//直接使用,不用加::
//相当于把Func放在了全局作用域
return 0;
}
特点:部分展开、安全性高、可以用于一个方法的多次使用
1.4.4 方式3:使用using namespace 命名空间名称 引入
#include <iostream>
using namespace std;
//将命名空间std全部展开,即所有的成员都可以直接使用,且不用加作用域解析运算符 ::
//一开始我们不清楚std里面有哪些成员,所以都展开,方便我们使用
//但是清楚了之后最好别加,可能会发生方式2中的两个time冲突的情况
using namespace n1::n2;
//因为time冲突,所以我们将n1中的n2全部展开
int main()
{
printf("a = %d, b = %d, c = %d\n", a, b, c);//n2中的a,b,c
printf("a + b = %d\n", Add(a , b));//n2中的Add函数
return 0;
}
特点:不指定访问(全部展开)、安全性低、方便直接使用命名空间中的每一个成员
使用命名空间可以帮助提高代码的可读性和可维护性,尤其在大型项目中,避免了全局命名冲突的问题。同时,C++标准库和第三方库也使用了命名空间来组织自己的代码。
二、输入和输出
2.1 标准输入对象cin 和 标准输出对象cout
- 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件 以及标准库的命名空间std。
- <<是流插入运算符,>>是流提取运算符。(与C语言中的移位运算符不同)
<<运算符被称为插入运算符(Insertion Operator),常用于对象向输出流的插入操作,即将数据写入输出流。
>> 运算符被称为提取运算符(Extraction Operator),常用于从输入流中提取数据,即从输入流中读取数据并存储到变量中。 - cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
- 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。 C++的输入输出可以自动识别变量类型。
void test1() { cout << "hello world" << endl; //C++的输入输出可以自动识别变量类型 int a; double b; char c; //从键盘上输入一个int类型的值传给a cin >> a; //从键盘上输入一个double类型的值传给b,一个char类型的值传给c cin >> b >> c; cout << "a = " << a << endl; cout << "b = " << b << ", c = " << c << endl; }
三、缺省参数
3.1 缺省参数的概念
在C++中,可以在函数声明或定义时给参数赋予一个默认的值。如果调用函数时没有提供相应的参数,将使用参数默认的值,否则使用提供的参数。
void Func(int a = 20)
{
cout << a << endl;
}
int main()
{
Func();//没有参数就使用缺省值20
Func(1);//提供参数就使用指定的参数1
return 0;
}
3.2 全缺省参数
全缺省参数指的是所有参数都具有默认值的情况。在函数声明或定义中,可以为每个参数提供默认值,从而使得调用函数时可以选择性地提供参数。
void Func1(int a = 10, int b = 20, int c = 30)
{
cout << "全缺省参数" << endl;
cout << "a = " << a << " ";
cout << "b = " << b << " ";
cout << "c = " << c << endl;
}
int main()
{
Func1(); //a,b,c全是缺省值
Func1(7); //b,c是缺省值,a是指定值
Func1(7, 8); //c是缺省值,a,b是指定值
Func1(7, 8, 9); //a,b,c全是指定值
return 0;
}
3.3 半缺省参数
半缺省参数指的是在函数声明或定义中只有一部分参数具有默认值的情况。尽管其他参数没有默认值,但在调用函数时仍然可以选择性地省略这些参数。
//半缺省参数
void Func2(int a, int b = 10, int c = 20)
{
cout << "半缺省参数" << endl;
cout << "a = " << a << " ";
cout << "b = " << b << " ";
cout << "c = " << c << endl;
}
int main()
{
//Func2();//不是缺省参数的必须给值
Func2(7);
Func2(7, 8);
Func2(7, 8, 9);
return 0;
}
3.4 缺省参数的注意事项
- 在函数声明或定义中,全缺省参数和半缺省参数的默认值只能从函数的最右边连续的参数上指定。也就是说,如果某个参数具有默认值,则其后的所有参数都必须具有默认值。
//不能存在两边有默认参数,中间没有的情况 void Func2(int a = 10, int b, int c = 20) { cout << "a = " << a << " "; cout << "b = " << b << " "; cout << "c = " << c << endl; } //报错:error C2548: “Func3”: 缺少形参 2 的默认实参
- 全缺省和半缺省在使用时参数必须从左往右依次给出(语法规定)
- 缺省参数不能在函数声明和定义中同时出现
缺省参数的值只能在函数声明或定义中指定一次,这是为了避免在不同的编译单元中出现多个默认参数值的定义,从而引发二义性错误。// 声明 void foo(int x = 0); // 定义 void foo(int x = 1) { // 函数实现 } //如果在调用函数 foo 时没有提供参数,则在编译时无法确定应该使用哪个默认参数值。
// 声明 void foo(int x = 0); // 定义 void foo(int x) { // 函数实现 } //为了避免这种二义性,C++规定只能在函数声明或定义中指定一次默认参数值。