C++ 命名空间 & 模板

命名空间

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

定义命名空间

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

namespace namespace_name {
   // 代码声明
}

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

namespace_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_space

using 指令

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

using namespace First_space;

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

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

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

不连续的命名空间

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

namespace namespace_Name {
   // 代码声明
}

嵌套的命名空间

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

namespace namespace_Name1 {
   // 代码声明
   namespace namespace_Name2 {
      // 代码声明
   }
}

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

/* 访问 namespace_name1 中的成员 */
using namespace namespace_Name1;

/* 访问 namespace_name2 中的成员 */ 
using namespace namespace_Name1::namespace_Name2;
 

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

#include <iostream>
using namespace std;

namespace A
{
    int a = 100;
    namespace B      //嵌套一个命名空间B
    {
        int a =20;
    }
}

int a = 200;         //定义一个全局变量

int main()
{
    cout <<"A::a ="<< A::a << endl;
    cout <<"A::B::a ="<< A::B::a << endl;
    cout <<"a ="<< a << endl;         // 全局变量 a   
    cout <<"::a ="<< ::a << endl;     // 全局变量 a 

    /* 添加一个同名局部变量,注意局部变量和全局变量的区分 */
    int a = 30;                       // 局部变量 a
    cout <<"局部变量 a ="<< a << endl;
    cout <<"::a ="<< ::a << endl;     // 全局变量 a 

    return 0;
}

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

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

模板

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

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

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

函数模板

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

template <typename Type> 
return_Type func_Name(parameter list)
{
   // 函数的主体
}

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

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

template <class T1, class T2>
void print(T1 arg1, T2 arg2)
{
  cout << arg1 <<" "<< arg2 << endl; 
}

template <class T>
void print(T arg1, T arg2)
{
  cout << arg1 <<" "<< arg2 << endl;
}

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

#include <iostream>
#include <string>

using namespace std;

template <typename T>
inline T const& Max(T const& a,T const& b)
{
	return a < b ? b:a;
}

int main()
{
   int i = 30;	
   int j = 20;	
   cout<<"Max(i,j): "<<Max(i,j)<<endl;
   
   string s1 = "hello";
   string s2 = "world";
   cout<<"Max(si,s2): "<<Max(s1,s2)<<endl;
   
   return 0;
}

         执行结果如下:

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

类模板

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

template <class type> 
class class_Name
{
    ...
}

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

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

template <typename type> 
class class_Name
{
    ...
}

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

#include<iostream>
#include<vector>
#include<cstdlib>
#include<string>
#include<stdexcept>

using namespace std;

template <class T>
class Stack
{
private:
    vector<T> elements;
public:
    void Push(T const&);
	void Pop();
	T Top() const;
	bool empty() const
	{
		return elements.empty();
	}
};

template <class T>
void Stack<T>::Push(T const& elem)
{
	elements.push_back(elem);
}

template <class T>
void Stack<T>::Pop () 
{ 
    if (elements.empty()) { 
        throw out_of_range("Stack<>::pop(): empty stack"); 
    }
    // 删除最后一个元素
    elements.pop_back();         
} 

template <class T>
T Stack<T>::Top() const
{
    if(elements.empty())
	{
        throw out_of_range("Stack<T>::Top(): empty stack");      
	}		
	return elements.back();
}

int main()
{
	try{
		Stack<int> intStack;
		Stack<string> stringStack;
		
		intStack.Push(7);
		cout<<intStack.Top()<<endl;
		
		stringStack.Push("hello");
		cout<<stringStack.Top()<<std::endl;
		stringStack.Pop();
		stringStack.Pop();
	} catch(exception const& ex) {
		cerr<<"exception: "<<ex.what()<<endl;
		return -1;
	}
	
    return 0;
}

         执行结果如下:

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

文章来源地址https://uudwc.com/A/vmdaw

原文地址:https://blog.csdn.net/weixin_60461563/article/details/132659158

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

h
上一篇 2023年09月14日 22:52
Windows环境下Springboot3+Graalvm+Idea 打包成原生镜像 踩坑
下一篇 2023年09月14日 22:52