目录
第一节:命名空间
1-1.什么是命名空间
在C语言中,如果多个变量使用同一个名字,就会出现重定义的问题。而在日常工作中,难免会出现不同程序员写出的不同头文件,它们中有相同名字的变量,但是被同一个文件引用的情况。为了解决这个问题,C++引入了命名空间,它允许存在不同命名空间的相同变量名。
一个命名空间的定义如下:
namespace csdn
{
int a = 3;
};
csdn 就是这个命名空间的名字;namespace 关键字标识csdn是一个命名空间;a 就是里面的一个变量。
1-2.命名空间与变量
如果要在命名空间外使用命名空间里的变量,需要遵循:命名空间::变量 的格式,以下是一个例子:
#include <stdio.h>
namespace csdn
{
int a = 3;
};
int main()
{
printf("%d\n", csdn::a);
return 0;
}
如果我在另外一个命名空间定义变量 a,它和 csdn 中的 a 不是同一个 a ,并且可以同时使用:
#include <stdio.h>
namespace csdn
{
int a = 3;
};
namespace CSDN
{
int a = 1;
};
int main()
{
printf("%d\n", csdn::a);
printf("%d\n", CSDN::a);
return 0;
}
在命名空间中使用自己的变量不需要遵循上述格式:
#include <stdio.h>
namespace csdn
{
int a = 3;
int b = a+1;
};
int main()
{
printf("%d\n", csdn::b);
return 0;
}
1-3.命名空间与其他结构
除了变量,命名空间里还能定义结构体类型和函数:
#include <stdio.h>
namespace csdn
{
struct student // 结构体类型
{
char name[20];
char id[20];
int age;
};
int Add(int x, int y) // 函数
{
return x + y;
}
};
int main()
{
struct csdn::student Eric; // 用命名空间中的结构体类型定义变量
int sum = csdn::Add(1,2); // 调用命名空间中的函数
printf("%d\n",sum);
return 0;
}
命名空间里还能嵌套命名空间,访问变量的格式是:外层命名空间::内存命名空间::变量:
#include <stdio.h>
namespace csdn
{
namespace CSDN // 嵌套命名空间
{
int a = 3;
};
};
int main()
{
printf("%d\n",csdn::CSDN::a);
return 0;
}
1-4.展开命名空间
如果感觉每次访问变量都需要加命名空间前缀比较麻烦,我们可以使用以下语句将命名空间展开,展开后里面的变量就变成全局变量了:
#include <stdio.h>
namespace csdn
{
int a = 3;
};
using namespace csdn; // 展开命名空间
int main()
{
printf("%d\n",a); // 无需前缀
return 0;
}
在C++库中,有一个所有库共用的命名空间,名为 std,在使用C++库中的各种数据结构、函数时,一般都需要加 std:: 前缀或者将它展开方便写代码。
第二节:流操作
C++中为了简化 fprintf 和 fscanf 函数,引入了流插入和流提取,它的本质也是函数,但是是以后要讲的类重载函数。
进行流操作需要包含头文件 <iostream>
2-1.流插入
流插入用于将变量插入到一个文件中,我们现在只需要用它向屏幕输出:
#include <iostream>
int main()
{
int a = 0;
std::cout << "a=" << a << std::endl; // 流插入
return 0;
}
cout是屏幕;<< 是流插入;endl表示换行;std 是命名空间。
上述代码可以理解为cout屏幕之后的各种字符串和变量按次序"流入"屏幕,然后打印出来,使用它打印不需要写出"%s"、"%d"等,它会自动识别。
2-2.流提取
流提取用于从文件中提取数据,我们现在从键盘提取数据:
#include <iostream>
int main()
{
int a,b;
std::cin >> a >> b;
std::cout << a << " " << b << std::endl;
return 0;
}
cin是键盘;>> 是流提取;std 是命名空间。
上述代码可以理解为数据从键盘中"流出",按次序赋值给后面的变量,使用它不需要 & 符号,也不需要写出"%s"、"%d"等,它会自动识别。
但是需要注意的是被提取之后,被提取的文件内容为空。
第三节:函数缺省、重载
函数的缺省与重载是C++引入的新特性,缺省允许函数的参数有一个默认值(可选择不传入参数,它有一个默认值),重载允许同名函数的出现。
3-1.函数缺省
有缺省参数的函数叫做缺省函数,一个缺省函数的定义如下:
int Add(int x, int y = 1) // 参数y缺省
{
return x + y;
}
当我们调用它时,如果不传入第二个参数,那它就会默认y=1,1就是y的缺省值:
int main()
{
std::cout << Add(2) << std::endl; // 不传第二个参数
std::cout << Add(2,3) << std::endl; // 传入第二个参数
return 0;
}
可见,缺省参数方便了函数的调用,对于一些参数大多数都使用同一个值得情况,就可以使用缺省参数。
注意,缺省参数必须放在最后,不能放在非缺省参数之前,即以下写法是不被允许的:
int Add(int x = 1, int y) // x缺省但y不缺省
{
return x + y;
}
因为这样无法在第一个参数使用缺省值的情况下给第二个参数传参,就失去意义了。
缺省函数的声明与定义分离时,只能在声明处给缺省值,定义处不能给缺省值:
int Add(int x, int y = 1); // 函数声明
int Add(int x, int y) // 函数定义
{
return x + y;
}
3-2.函数重载
C语言中是不允许同名函数的,但是C++中允许同名函数的出现,参数符合以下3个条件之一即可:
(1)函数的参数类型不同:
int Add(int x, int y) // 第一个参数类型是 int
{
std::cout << "我是第一个函数" << std::endl;
return x + y;
}
int Add(double x, int y)// 第一个参数类型是 double
{
std::cout << "我是第二个函数" << std::endl;
return x + y;
}
当你调用 Add 函数时,编译器会根据你传入的实参类型匹配最佳函数,因为有隐式类型转换,两个函数的参数都可以传入浮点型,但是编译器会匹配最合适的第二个函数:
int main()
{
Add(1.0,2);
Add(1, 2);
return 0;
}
(2)函数的参数个数不同:
int Add(int x, int y) // 2个参数
{
std::cout << "我是第一个函数" << std::endl;
return x + y;
}
int Add(int x, int y,int z)// 3个参数
{
std::cout << "我是第二个函数" << std::endl;
return x + y + z;
}
调用时,也会匹配最佳函数:
int main()
{
Add(1,2,3);
Add(1, 2);
return 0;
}
但是如果有缺省参数,可能就会使函数重载失效,请看以下案例:
第2个参数的第3个参数设置成缺省参数,这就会导致Add(1,2)出现重定义错误,这是因为第1个函数和第2个函数都可以这样调用,它不知道该匹配哪个函数。
综上所述,函数重载的核心就是保持一个唯一性。
(3)函数的参数顺序不同:
int Add(int x, double y) // double类型在后面
{
std::cout << "我是第一个函数" << std::endl;
return x + y;
}
int Add(double x, int y)// double类型在前面
{
std::cout << "我是第二个函数" << std::endl;
return x + y;
}
编译器也会根据实参匹配最佳函数:
int main()
{
Add(1.0,2); // 第一个实参是double类型
Add(1,2.0); // 第二个实参是double类型
return 0;
}
下期预告:
下一次我们会将以下内容:
(1)引用:给变量取别名
(2)结构体中的成员函数:面向对象编程的基础
(3)inline函数:原地展开,不建立栈帧的函数
(4)auto关键字:自动类型识别