• C++ 命名空间 & 模板


    命名空间

             为了区分不同库中相同名称的函数、类、变量等,引入概念:命名空间。它可作为附加信息来帮助区分它们。使用了命名空间即定义了上下文,本质上就是定义了一个范围。         

    定义命名空间

             命名空间的定义使用关键字 namespace,后跟命名空间的名称,如下所示:

    1. namespace namespace_name {
    2. // 代码声明
    3. }

             为了调用带有命名空间的函数或变量,需要在前面加上命名空间的名称,如下所示:

    namespace_name::code;    // code 可以是变量或函数

             命名空间为变量或函数等实体定义范围的实例:

    1. #include
    2. using namespace std;
    3. /* 第一个命名空间 */
    4. namespace First_space{
    5. void func()
    6. {
    7. cout<<"Inside first_space"<
    8. }
    9. }
    10. /* 第二个命名空间 */
    11. namespace Second_space{
    12. void func()
    13. {
    14. cout<<"Inside second_space"<
    15. }
    16. }
    17. int main()
    18. {
    19. First_space::func(); // 调用第一个命名空间中的函数
    20. Second_space::func(); // 调用第二个命名空间中的函数
    21. return 0;
    22. }

             执行结果如下:

    Inside first_space
    Inside second_space

    using 指令

             在使用命名空间时,用 using namespace 指令,就可以不用在函数或变量前面加上命名空间的名称。这个指令会告诉编译器,后续的代码将使用指定的命名空间中的名称。

    using namespace First_space;

             using 指令也可以用来指定命名空间中的特定项目,在随后的代码中,就可以不用加上命名空间名称作为前缀了。但是 std 命名空间中的其他项目仍然需要加上命名空间名称作为前缀。例如,只打算使用命名空间 std 中的 cout 部分,如下所示:

    1. #include
    2. using std::cout; // 指定命名空间中的的 cout
    3. int main ()
    4. {
    5. /* 没有指定 std 中的 endl, 仍然需要加上命名空间名称作为前缀 */
    6. cout << "std::endl is used with std!" << std::endl;
    7. return 0;
    8. }

             using 指令引入的名称遵循正常的范围规则。名称从使用 using 指令开始是可见的,直到该范围结束。此时,在范围以外定义的同名实体是隐藏的。

    不连续的命名空间

             命名空间可以定义在几个不同的部分中,因此命名空间是由几个单独定义的部分组成的。一个命名空间的各个组成部分可以分散在多个文件中。所以,如果命名空间中的某个组成部分需要请求定义在另一个文件中的名称,则仍然需要声明该名称。下面的命名空间定义可以是定义一个新的命名空间,也可以是为已有的命名空间增加新的元素:

    1. namespace namespace_Name {
    2. // 代码声明
    3. }

    嵌套的命名空间

             命名空间可以嵌套,即,在一个命名空间中定义另一个命名空间,如下所示:

    1. namespace namespace_Name1 {
    2. // 代码声明
    3. namespace namespace_Name2 {
    4. // 代码声明
    5. }
    6. }

             并通过使用 :: 运算符来访问嵌套的命名空间中的成员:

    1. /* 访问 namespace_name1 中的成员 */
    2. using namespace namespace_Name1;
    3. /* 访问 namespace_name2 中的成员 */
    4. using namespace namespace_Name1::namespace_Name2;

             注意:使用 namespace_Name1,那么在该范围内的 namespace_Name2 中的元素也是可用的,如下所示:

    1. #include
    2. using namespace std;
    3. namespace A
    4. {
    5. int a = 100;
    6. namespace B //嵌套一个命名空间B
    7. {
    8. int a =20;
    9. }
    10. }
    11. int a = 200; //定义一个全局变量
    12. int main()
    13. {
    14. cout <<"A::a ="<< A::a << endl;
    15. cout <<"A::B::a ="<< A::B::a << endl;
    16. cout <<"a ="<< a << endl; // 全局变量 a
    17. cout <<"::a ="<< ::a << endl; // 全局变量 a
    18. /* 添加一个同名局部变量,注意局部变量和全局变量的区分 */
    19. int a = 30; // 局部变量 a
    20. cout <<"局部变量 a ="<< a << endl;
    21. cout <<"::a ="<< ::a << endl; // 全局变量 a
    22. return 0;
    23. }

             全局变量 a 表达为 ::a,用于当有同名的局部变量时来区别两者。执行结果如下:

    A::a =100
    A::B::a =20
    a =200
    ::a =200
    局部变量 a =30
    ::a =200

    模板

             模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。

             模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。每个容器都有一个单一的定义,比如 向量(vector),我们可以定义许多不同类型的向量,比如 vector  或 vector

             可以使用模板来定义函数和类,接下来让我们一起来看看如何使用。

    函数模板

             模板函数定义的一般形式如下所示:

    1. template <typename Type>
    2. return_Type func_Name(parameter list)
    3. {
    4. // 函数的主体
    5. }

             在这里,Type 是函数所使用的数据类型的占位符名称。这个名称可以在函数定义中使用。

             函数模板可以重载,只要它们的形参表不同即可。例如,下面两个模板可以同时存在:

    1. template <class T1, class T2>
    2. void print(T1 arg1, T2 arg2)
    3. {
    4. cout << arg1 <<" "<< arg2 << endl;
    5. }
    6. template <class T>
    7. void print(T arg1, T arg2)
    8. {
    9. cout << arg1 <<" "<< arg2 << endl;
    10. }

             下面是函数模板的实例,返回两个数中的最大值:

    1. #include
    2. #include
    3. using namespace std;
    4. template <typename T>
    5. inline T const& Max(T const& a,T const& b)
    6. {
    7. return a < b ? b:a;
    8. }
    9. int main()
    10. {
    11. int i = 30;
    12. int j = 20;
    13. cout<<"Max(i,j): "<<Max(i,j)<
    14. string s1 = "hello";
    15. string s2 = "world";
    16. cout<<"Max(si,s2): "<<Max(s1,s2)<
    17. return 0;
    18. }

             执行结果如下:

    Max(i,j): 30
    Max(si,s2): world

    类模板

              类模板泛型类声明的一般形式如下所示:

    1. template <class type>
    2. class class_Name
    3. {
    4. ...
    5. }

              type 是占位符类型名称,可以在类被实例化的时候进行指定。使用一个逗号分隔的列表可以定义多个泛型数据类型。

              在模板定义语法中关键字 class 与 typename 的作用完全一样,所以类模板泛型类声明也可以是这样:

    1. template <typename type>
    2. class class_Name
    3. {
    4. ...
    5. }

              下面的实例定义了类 Stack<>,并实现了泛型方法来对元素进行入栈出栈操作:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. template <class T>
    8. class Stack
    9. {
    10. private:
    11. vector elements;
    12. public:
    13. void Push(T const&);
    14. void Pop();
    15. T Top() const;
    16. bool empty() const
    17. {
    18. return elements.empty();
    19. }
    20. };
    21. template <class T>
    22. void Stack::Push(T const& elem)
    23. {
    24. elements.push_back(elem);
    25. }
    26. template <class T>
    27. void Stack::Pop ()
    28. {
    29. if (elements.empty()) {
    30. throw out_of_range("Stack<>::pop(): empty stack");
    31. }
    32. // 删除最后一个元素
    33. elements.pop_back();
    34. }
    35. template <class T>
    36. T Stack::Top() const
    37. {
    38. if(elements.empty())
    39. {
    40. throw out_of_range("Stack::Top(): empty stack");
    41. }
    42. return elements.back();
    43. }
    44. int main()
    45. {
    46. try{
    47. Stack<int> intStack;
    48. Stack stringStack;
    49. intStack.Push(7);
    50. cout<Top()<
    51. stringStack.Push("hello");
    52. cout<Top()<
    53. stringStack.Pop();
    54. stringStack.Pop();
    55. } catch(exception const& ex) {
    56. cerr<<"exception: "<what()<
    57. return -1;
    58. }
    59. return 0;
    60. }

             执行结果如下:

    7
    hello
    exception: Stack<>::pop(): empty stack

  • 相关阅读:
    【华为机试真题 JAVA】输出指定字母在字符串的中的索引-100
    测开 (性能测试)
    3D印刷电路板在线渲染查看工具
    基于 GD32F450 的Zephyr 的基本测试-编译工程
    HTTP请求拦截器链
    阿里云/腾讯云被攻击后怎么秒解黑洞
    CSS学习221~249(定位+元素的显示隐藏)
    Python入门 | 如何判断多个条件
    【DevOps基础篇之k8s】如何应用Kubernetes中的Role Based Access Control(RBAC)
    ping: mirrors.aliyun.com: Temporary failure in name resolution
  • 原文地址:https://blog.csdn.net/weixin_60461563/article/details/132659158