宁波住房和城乡建设局网站,wordpress优劣,一级建造师报考条件2022考试时间,大米包装设计一 命名空间
假设这样一种情况#xff0c;当一个班上有两个名叫 Zara 的学生时#xff0c;为了明确区分它们#xff0c;我们在使用名字之外#xff0c;不得不使用一些额外的信息#xff0c;比如他们的家庭住址#xff0c;或者他们父母的名字等等。
同样的情况也出现在 …一 命名空间
假设这样一种情况当一个班上有两个名叫 Zara 的学生时为了明确区分它们我们在使用名字之外不得不使用一些额外的信息比如他们的家庭住址或者他们父母的名字等等。
同样的情况也出现在 C 应用程序中。例如您可能会写一个名为 xyz() 的函数在另一个可用的库中也存在一个相同的函数 xyz()。这样编译器就无法判断您所使用的是哪一个 xyz() 函数。
因此引入了命名空间这个概念专门用于解决上面的问题它可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。本质上命名空间就是定义了一个范围。
我们举一个计算机系统中的例子一个文件夹(目录)中可以包含多个文件夹每个文件夹中不能有相同的文件名但不同文件夹中的文件可以重名。 1.1 定义命名空间
命名空间的定义使用关键字 namespace后跟命名空间的名称如下所示
namespace namespace_name {// 代码声明
}
为了调用带有命名空间的函数或变量需要在前面加上命名空间的名称如下所示
name::code; // code 可以是变量或函数
命名空间如何为变量或函数等实体定义范围
#include iostream
using namespace std;// 第一个命名空间
namespace first_space{void func(){cout Inside first_space endl;}
}
// 第二个命名空间
namespace second_space{void func(){cout Inside second_space endl;}
}
int main ()
{// 调用第一个命名空间中的函数first_space::func();// 调用第二个命名空间中的函数second_space::func(); return 0;
}
输出
Inside first_space
Inside second_space1.2 using 指令
您可以使用 using namespace 指令这样在使用命名空间时就可以不用在前面加上命名空间的名称。这个指令会告诉编译器后续的代码将使用指定的命名空间中的名称。
#include iostream
using namespace std;// 第一个命名空间
namespace first_space{void func(){cout Inside first_space endl;}
}
// 第二个命名空间
namespace second_space{void func(){cout Inside second_space endl;}
}
using namespace first_space;
int main ()
{// 调用第一个命名空间中的函数func();return 0;
}
输出
Inside first_spaceusing 指令也可以用来指定命名空间中的特定项目。例如如果您只打算使用 std 命名空间中的 cout 部分
using std::cout;随后的代码中在使用 cout 时就可以不用加上命名空间名称作为前缀但是 std 命名空间中的其他项目仍然需要加上命名空间名称作为前缀如下所示
#include iostream
using std::cout;int main ()
{cout std::endl is used with std! std::endl;return 0;
}
输出
std::endl is used with std!using 指令引入的名称遵循正常的范围规则。名称从使用 using 指令开始是可见的直到该范围结束。此时在范围以外定义的同名实体是隐藏的。
1.3 不连续的命名空间
命名空间可以定义在几个不同的部分中因此命名空间是由几个单独定义的部分组成的。一个命名空间的各个组成部分可以分散在多个文件中。
所以如果命名空间中的某个组成部分需要请求定义在另一个文件中的名称则仍然需要声明该名称。下面的命名空间定义可以是定义一个新的命名空间也可以是为已有的命名空间增加新的元素
namespace namespace_name {// 代码声明
}
1.4 嵌套的命名空间
命名空间可以嵌套您可以在一个命名空间中定义另一个命名空间如下所示
namespace namespace_name1 {// 代码声明namespace namespace_name2 {// 代码声明}
}
可以通过使用 :: 运算符来访问嵌套的命名空间中的成员
// 访问 namespace_name2 中的成员
using namespace namespace_name1::namespace_name2;// 访问 namespace_name1 中的成员
using namespace namespace_name1;
在上面的语句中如果使用的是 namespace_name1那么在该范围内 namespace_name2 中的元素也是可用的如下所示
#include iostream
using namespace std;// 第一个命名空间
namespace first_space{void func(){cout Inside first_space endl;}// 第二个命名空间namespace second_space{void func(){cout Inside second_space endl;}}
}
using namespace first_space::second_space;
int main ()
{// 调用第二个命名空间中的函数func();return 0;
}
输出
Inside second_space二 模板
模板是泛型编程的基础泛型编程即以一种独立于任何特定类型的方式编写代码。
模板是创建泛型类或函数的蓝图或公式。库容器比如迭代器和算法都是泛型编程的例子它们都使用了模板的概念。
每个容器都有一个单一的定义比如 向量我们可以定义许多不同类型的向量比如 vector int 或 vector string。
可以使用模板来定义函数和类接下来让我们一起来看看如何使用。
2.1 函数模板
模板函数定义的一般形式如下所示
template typename type ret-type func-name(parameter list)
{// 函数的主体
}
在这里type 是函数所使用的数据类型的占位符名称。这个名称可以在函数定义中使用。
下面是函数模板的实例返回两个数中的最大值
#include iostream
#include stringusing namespace std;template typename T
inline T const Max (T const a, T const b)
{ return a b ? b:a;
}
int main ()
{int i 39;int j 20;cout Max(i, j): Max(i, j) endl; double f1 13.5; double f2 20.7; cout Max(f1, f2): Max(f1, f2) endl; string s1 Hello; string s2 World; cout Max(s1, s2): Max(s1, s2) endl; return 0;
}
输出
Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World2.2 类模板
正如我们定义函数模板一样我们也可以定义类模板。泛型类声明的一般形式如下所示
template class type class class-name {
.
.
.
}在这里type 是占位符类型名称可以在类被实例化的时候进行指定。您可以使用一个逗号分隔的列表来定义多个泛型数据类型。
下面的实例定义了类 Stack并实现了泛型方法来对元素进行入栈出栈操作
#include iostream
#include vector
#include cstdlib
#include string
#include stdexceptusing namespace std;template class T
class Stack { private: vectorT elems; // 元素 public: void push(T const); // 入栈void pop(); // 出栈T top() const; // 返回栈顶元素bool empty() const{ // 如果为空则返回真。return elems.empty(); }
}; template class T
void StackT::push (T const elem)
{ // 追加传入元素的副本elems.push_back(elem);
} template class T
void StackT::pop ()
{ if (elems.empty()) { throw out_of_range(Stack::pop(): empty stack); }// 删除最后一个元素elems.pop_back();
} template class T
T StackT::top () const
{ if (elems.empty()) { throw out_of_range(Stack::top(): empty stack); }// 返回最后一个元素的副本 return elems.back();
} int main()
{ try { Stackint intStack; // int 类型的栈 Stackstring stringStack; // string 类型的栈 // 操作 int 类型的栈 intStack.push(7); cout intStack.top() endl; // 操作 string 类型的栈 stringStack.push(hello); cout stringStack.top() std::endl; stringStack.pop(); stringStack.pop(); } catch (exception const ex) { cerr Exception: ex.what() endl; return -1;}
}
输出
7
hello
Exception: Stack::pop(): empty stack三 预处理器
预处理器是一些指令指示编译器在实际编译之前所需完成的预处理。
所有的预处理器指令都是以井号#开头只有空格字符可以出现在预处理指令之前。预处理指令不是 C 语句所以它们不会以分号;结尾。
我们已经看到之前所有的实例中都有 #include 指令。这个宏用于把头文件包含到源文件中。
C 还支持很多预处理指令比如 #include、#define、#if、#else、#line 等让我们一起看看这些重要指令。
3.1 #define 预处理
#define 预处理指令用于创建符号常量。该符号常量通常称为宏指令的一般形式是
#define macro-name replacement-text 当这一行代码出现在一个文件中时在该文件中后续出现的所有宏都将会在程序编译之前被替换为 replacement-text。例如
#include iostream
using namespace std;#define PI 3.14159int main ()
{cout Value of PI : PI endl; return 0;
}
现在让我们测试这段代码看看预处理的结果。假设源代码文件已经存在接下来使用 -E 选项进行编译并把结果重定向到 test.p。现在如果您查看 test.p 文件将会看到它已经包含大量的信息而且在文件底部的值被改为如下
$ gcc -E test.cpp test.p...
int main ()
{cout Value of PI : 3.14159 endl; return 0;
}3.2 参数宏
可以使用 #define 来定义一个带有参数的宏如下所示
#include iostream
using namespace std;#define MIN(a,b) (ab ? a : b)int main ()
{int i, j;i 100;j 30;cout 较小的值为 MIN(i, j) endl;return 0;
}
输出
较小的值为303.3 条件编译
有几个指令可以用来有选择地对部分程序源代码进行编译。这个过程被称为条件编译。
条件预处理器的结构与 if 选择结构很像。请看下面这段预处理器的代码
#ifdef NULL#define NULL 0
#endif可以只在调试时进行编译调试开关可以使用一个宏来实现如下所示
#ifdef DEBUGcerr Variable x x endl;
#endif如果在指令 #ifdef DEBUG 之前已经定义了符号常量 DEBUG则会对程序中的 cerr 语句进行编译。您可以使用 #if 0 语句注释掉程序的一部分如下所示
#if 0不进行编译的代码
#endif实例
#include iostream
using namespace std;
#define DEBUG#define MIN(a,b) (((a)(b)) ? a : b)int main ()
{int i, j;i 100;j 30;
#ifdef DEBUGcerr Trace: Inside main function endl;
#endif#if 0/* 这是注释部分 */cout MKSTR(HELLO C) endl;
#endifcout The minimum is MIN(i, j) endl;#ifdef DEBUGcerr Trace: Coming out of main function endl;
#endifreturn 0;
}
输出
Trace: Inside main function
The minimum is 30
Trace: Coming out of main function3.4 # 和 ## 运算符
# 和 ## 预处理运算符在 C 和 ANSI/ISO C 中都是可用的。# 运算符会把 replacement-text 令牌转换为用引号引起来的字符串。
请看下面的宏定义
#include iostream
using namespace std;#define MKSTR( x ) #xint main ()
{cout MKSTR(HELLO C) endl;return 0;
}
输出
HELLO C让我们来看看它是如何工作的。不难理解C 预处理器把下面这行
cout MKSTR(HELLO C) endl;转换成了
cout HELLO C endl;## 运算符用于连接两个令牌。下面是一个实例
#define CONCAT( x, y ) x ## y当 CONCAT 出现在程序中时它的参数会被连接起来并用来取代宏。例如程序中 CONCAT(HELLO, C) 会被替换为 HELLO C如下面实例所示。
#include iostream
using namespace std;#define concat(a, b) a ## b
int main()
{int xy 100;cout concat(x, y);return 0;
}
输出
100让我们来看看它是如何工作的。不难理解C 预处理器把下面这行
cout concat(x, y);转换成了
cout xy;3.5 C中的预定义宏
宏描述__LINE__这会在程序编译时包含当前行号。__FILE__这会在程序编译时包含当前文件名。__DATE__这会包含一个形式为 month/day/year 的字符串它表示把源文件转换为目标代码的日期。__TIME__这会包含一个形式为 hour:minute:second 的字符串它表示程序被编译的时间。
实例
#include iostream
using namespace std;int main ()
{cout Value of __LINE__ : __LINE__ endl;cout Value of __FILE__ : __FILE__ endl;cout Value of __DATE__ : __DATE__ endl;cout Value of __TIME__ : __TIME__ endl;return 0;
}
输出
Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48