我們用到的庫函數基本上都屬於命名空間std的,在程序使用的過程中要顯示的將這一點標示出來,如std::cout。這個方法比較煩瑣,而我們都知道使用using聲明則更方便更安全。
2、命令空間的using聲明
我們在書寫模塊功能時,為了防止命名沖突會對模塊取命名空間,這樣子在使用時就需要指定是哪個命名空間,使用using聲明,則后面使用就無須前綴了。例如:
using std::cin; //using聲明,當我們使用cin時,從命名空間std中獲取它
int main()
{
int i;
cin >> i; //正確:cin和std::cin含義相同
cout << i; //錯誤:沒有對應的using聲明,必須使用完整的名字
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
需要注意的是每個名字需要獨立的using聲明。例如:
using std::cin; //必須每一個都有獨立的using聲明
using std::cout; using std::endl; //寫在同一行也需要獨立聲明
- 1
- 2
位於頭文件的代碼一般來說不應該使用using聲明。因為頭文件的內容會拷貝到所有引用它的文件中去,如果頭文件里有某個using聲明,那么每個使用了該頭文件的文件就都會有這個聲明,有可能產生名字沖突。
3、在子類中引用基類成員
在子類中對基類成員進行聲明,可恢復基類的防控級別。有三點規則:
- 在基類中的private成員,不能在派生類中任何地方用using聲明。
- 在基類中的protected成員,可以在派生類中任何地方用using聲明。當在public下聲明時,在類定義體外部,可以用派生類對象訪問該成員,但不能用基類對象訪問該成員;當在protected下聲明時,該成員可以被繼續派生下去;當在private下聲明時,對派生類定義體外部來說,該成員是派生類的私有成員。
- 在基類中的public成員,可以在派生類中任何地方用using聲明。具體聲明后的效果同基類中的protected成員。
例如:
class Base
{
protected:
void test1() { cout << "test1" << endl; }
void test1(int a) {cout << "test2" << endl; }
int value = 55;
};
class Derived : Base //使用默認繼承
{
public:
//using Base::test1; //using只是聲明,不參與形參的指定
//using Base::value;
void test2() { cout << "value is " << value << endl; }
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
我們知道class的默認繼承是private,這樣子類中是無法訪問基類成員的,即test2會編譯出錯。但是如果我們把上面注釋的聲明給放開,則沒有問題。
注意:using::test1只是聲明,不需要形參指定,所以test1的兩個重載版本在子類中都可使用。
4、使用using起別名
相當於傳統的typedef起別名。
typedef std::vector<int> intvec;
using intvec = std::vector<int>; //這兩個寫法是等價的
- 1
- 2
這個還不是很明顯的優勢,在來看一個列子:
typedef void (*FP) (int, const std::string&);
- 1
若不是特別熟悉函數指針與typedef,第一眼還是很難指出FP其實是一個別名,代表着的是一個函數指針,而指向的這個函數返回類型是void,接受參數是int, const std::string&。
using FP = void (*) (int, const std::string&);
- 1
這樣就很明顯了,一看FP就是一個別名。using的寫法把別名的名字強制分離到了左邊,而把別名指向的放在了右邊,比較清晰,可讀性比較好。比如:
typedef std::string (Foo::* fooMemFnPtr) (const std::string&);
using fooMemFnPtr = std::string (Foo::*) (const std::string&);
- 1
- 2
- 3
來看一下模板別名。
template <typename T>
using Vec = MyVector<T, MyAlloc<T>>;
// usage
Vec<int> vec;
- 1
- 2
- 3
- 4
- 5
若使用typedef
template <typename T>
typedef MyVector<T, MyAlloc<T>> Vec;
// usage
Vec<int> vec;
- 1
- 2
- 3
- 4
- 5
當進行編譯的時候,編譯器會給出error: a typedef cannot be a template的錯誤信息。
那么,如果我們想要用typedef做到這一點,需要進行包裝一層,如:
template <typename T>
struct Vec
{
typedef MyVector<T, MyAlloc<T>> type;
};
// usage
Vec<int>::type vec;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
正如你所看到的,這樣是非常不漂亮的。而更糟糕的是,如果你想要把這樣的類型用在模板類或者進行參數傳遞的時候,你需要使用typename強制指定這樣的成員為類型,而不是說這樣的::type是一個靜態成員亦或者其它情況可以滿足這樣的語法,如:
template <typename T>
class Widget
{
typename Vec<T>::type vec;
};
- 1
- 2
- 3
- 4
- 5
然而,如果是使用using語法的模板別名,你則完全避免了因為::type引起的問題,也就完全不需要typename來指定了。
template <typename T>
class Widget
{
Vec<T> vec;
};
- 1
- 2
- 3
- 4
- 5
一切都會非常的自然,所以於此,模板起別名時推薦using,而非typedef。
所謂namespace,是指標識符的各種可見范圍。C++標准程序庫中的所有標識符都被定義於一個名為std的namespace中。
iostream和iostream.h的區別:
后綴為.h的頭文件C++標注已經明確提出不支持了。早些的實現將標准庫功能定義在全局空間里,聲明在帶.h后綴的頭文件里,C++標准為了和C區別開,也為了正確地使用命名空間,規定頭文件不使用后綴.h。因此,當使用<iostream.h>時,相當於在C中調用庫函數,使用的是全局命名空間,也就是早期的C++實現。當使用<iostream>時,該頭文件沒有定義全局命名空間,必須使用namespace std,這樣才能使用類似於cout這樣的C++標識符。
