0%

using 關鍵字在 C++ 中的幾種用法

摘要

using 關鍵字在 C++ 中的幾種用法

1. using 声明

using 聲明 (using declaration) 是將命名空間中單個名字註入到當前作用域的機製,

使得在當前作用域下訪問另一個作用域下的成員時無需使用限定符 ::

1
2
3
4
5
6
// ...
{
using std::map
map<int, std::string> the_map; //ok
}
map<int, std::string> the_map2; //error

using 聲明將其它 namespace 的成員引入本命名空間的 當前作用域 (包括其嵌套作用域) 。

一個 using 聲明一次只引入一個命名空間成員,它使得無論程序中使用哪些名字,都非常準確。

利用 using 聲明,可以改變派生類對父類成員的訪問控製:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Base{
protected:
int bn1;
int bn2;
};

class Derived: private Base{
public:
using Base::bn1;
};

class DerivedAgain: public Derived{
};

int main(){
Derived d;
DerivedAgain da;
d.bn1 = 1;
d.bn2 = 2; //error, 'bn2' is a private member of 'Base'
da.bn1 = 3; //ok
std::cout<<d.bn1<<std::endl;

return 0;
}

盡管 Derived 對 base 是私有繼承,但通過 using 聲明,我們還是可以在 Derived 中訪問其成員,

且後續的繼承同樣不受 private 限定的影響。

2. using 指示 (引入命名空間)

using 指示 (using directive) 是使一個命名空間中的 所有 名字都在該作用域中可見的機製。

這是最常用的方式了。需要註意的是命名沖突問題。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
namespace n1{
int n1_member = 10;
int m = 11;
}

int m = 12;

int main(){
using namespace n1;
std::cout<<n1_member<<std::endl;
//std::cout<<m<<std::endl; //error 命名沖突
std::cout<<::m<<std::endl;

int m = 13; //ok, 局部變量屏蔽命名空間變量
std::cout<<m<<std::endl;

return 0;
}

Notice: 盡管 using指示很方便,但在實際工作中應該盡量避免:

它一下子將另一個 namespace 中的成員全部引入了,一不小心就會出現命名空間汙染問題。

3. 類型重定義,取代 typedef

1
using alias = typename

這是 C++11 中的新用法,比 typedef 更能表達別名的定義。

1
2
3
4
5
6
7
8
using fun = void (*)(int, int);
//typedef void (*fun)(int, int); //與上一句等價
using int16 = short;
//typedef short int16; //與上一句等價

int main(){
std::cout<<sizeof(int16)<<std::endl;
}

在 C++98/03 中 ,typedef 重定義有一些限製,比如,模板。

我們想實現這樣一個模板:將一個 int 映射到任意類型,類似於我們想表達這種效果:

1
2
3
4
typedef std::map<int, int> map_int_t;
typedef std::map<int, std::string> map_str_t;
typedef std::map<int, bool> map_b_t;
//... Others

我們在 C++98/03 中必須這樣寫:

1
2
3
4
5
6
7
8
9
10
template<typename Val>
struct int_map{
typedef std::map<int, Val> type;
};

int main(){
int_map<int>::type imap;

return 0;
}

在C++11 中,我們可以使用 using 重定義模板 :

1
2
3
4
5
6
7
8
template<typename Val>
using int_map_t = std::map<int, Val>;

int main(){
int_map_t<int> imap;

return 0;
}

歡迎關注我的其它發布渠道