1 / 42

Chap 16 名稱空間

Chap 16 名稱空間. 子曰:「名不正,則言不順 ﹔ 言不順,則事不成。」 《 論語 ﹒ 子路第十三 》 名稱空間 (namespace) 的目的在於避免大型程式庫之間因為使用相同名稱而造成衝突。. Chap 16 名稱空間. 16.1  因為名稱相同而造成的問題 16.2  名稱空間的基本語法 16.3  名稱空間成員的存取 16.4  使用「 using 指令」和「 using 宣 告」以存取名稱空間的成員 16.5  標準名稱空間 16.6  未命名的名稱空間. 因為名稱相同而造成的問題.

Download Presentation

Chap 16 名稱空間

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chap 16 名稱空間 子曰:「名不正,則言不順﹔言不順,則事不成。」 《論語﹒子路第十三》 名稱空間 (namespace)的目的在於避免大型程式庫之間因為使用相同名稱而造成衝突。

  2. Chap 16 名稱空間 • 16.1 因為名稱相同而造成的問題 • 16.2 名稱空間的基本語法 • 16.3 名稱空間成員的存取 • 16.4 使用「using指令」和「using宣 告」以存取名稱空間的成員 • 16.5 標準名稱空間 • 16.6 未命名的名稱空間

  3. 因為名稱相同而造成的問題 • 開發大型程式時,因為名稱相同而造成問題的機會就會大增。 • 限制了我們使用同名常數和同名類別的機會,否則在編譯時就會發生重複宣告(multiple declaration) 的錯誤,無法正確使用程式庫 (library)。

  4. 因為名稱衝突而造成無法引用既有程式的問題 • 由於常數Gain和struct資料型態Member的名稱相同,一次只能選擇一個標頭檔使用

  5. 名稱空間的基本語法 • 名稱空間 (name space) 的宣告敘述之後沒有「;」做為結尾。例如: namespace MyNamespace // 程式庫的介面 { const double Gain = 5.9; // 常數的定義 struct Member // struct資料型態的宣告 { char Name[20]; int Phone; }; double Fnc(double); // 函數的宣告(函數的原型) }

  6. 名稱空間的宣告可以用累積的方式完成 namespace MyNamespace { const double Gain = 5.9; } namespace MyNamespace { struct Member { char Name[20]; int Phone; }; double Fnc(double); }

  7. 名稱空間成員的存取 • 名稱空間的成員(member): 名稱空間所含的各個項目。 • 「::」: 範圍確認運算子(scope resolution operator) 。 • 要存取名稱空間的成員時:名稱空間的名稱 + 範圍確認運算子 + 該成員的名稱。 • 例如: MyNamespace::Gain; MyNamespace::Fnc();

  8. 資格修飾子(qualifier) • 資格修飾子: 名稱空間的名稱加上範圍確認運算子。「MyNamespace::」就是一個典型的資格修飾子。 • 使用名稱空間中宣告的struct資料型態來定義實例(instance) : MyNamespace::Member Ma = {"George Wang", 23246352}; • 也就是說,耍在struct資料型態的名稱前加上資格修飾子。

  9. 巢狀名稱空間 (nested namespace) • 名稱空間的成員是另一個名稱空間。例如: namespace NS1 { int Size; namespace NS2 { const double Ratio; } } • 巢狀名稱空間的內部成員必需套用所有名稱空間的名稱: int x = NS1::Size; double y = NS1::NS2::Ratio;

  10. 名稱空間的別名 (alias) • 簡化超長的名稱空間名稱。例如,有個名稱很長的名稱空間: namespace Micro_Soft-Company_Namespace { char Employer[2500][20]; double Fnc(double); } • 可以使用名稱空間別名敘述 (namespace alias statement ): namespace MSC = Micro_Soft-Company_Namespace;

  11. 使用名稱空間別名 (alias) 存取成員 • 可以使用較簡短的方式存取其成員,例如: char Head[20] = MSC::Employer[23]; • 使用名稱空間別名敘述可以一次取代兩層巢狀名稱空間的關係: namespace NS12 = NS1::NS2; • 此後成員的存取就可以精簡成: double y = NS12::Ratio;

  12. 程式庫的分割: 介面與實作 • 介面部份(interface part): 包括常數宣告和函數原型的部份。 • 實作部份(implementation part): 含有演算細節之函數定義的部份。 • 通常進一步將龐大的程式庫區分成數個檔案。譬如說,可以將「介面部份」儲存成一個叫做MyLib.h的檔案,而將「實作部份」儲存成一個稱為MyLib.cpp的檔案。

  13. 實作部份的寫法 (1/2) • 在名稱空間主體之中定義函數例如: // MyLib.cpp #include "MyLib.h" namespace MyNamespace { double Fnc(double x) { // 函數 Fnc() 的演算細節 } }

  14. 實作部份的寫法 (2/2) • 在名稱空間主體之外定義函數例如: // MyLib.cpp #include "MyLib.h" double MyNamespace::Fnc(double x) { // 函數Fnc()的演算細節 }

  15. 實例介紹 • 在檔案First.h和Second.h內,分別宣告了NS1和NS2兩個名稱空間。NS1和NS2兩個名稱空間的同名函數Fnc() 實作部份寫在檔案 FncLib.cpp裏面。 • 檔案Test.cpp是主程式,分別使用名稱空間NS1和NS2中的各成員。 • 以Borland C++ Command Line Compiler的使用方式為例,本程式在DOS下的編譯指令為: bcc32 Test FncLib

  16. 範例程式 檔案 First.h // First.h #ifndef FIRST_H #define FIRST_H namespaceNS1 // 宣告名稱空間 NS1 { const double Gain = 5.9; struct Member { char Name[20]; int Phone; }; double Fnc(double); } #endif

  17. 範例程式 檔案 Second.h // Second.h #ifndef SECOND_H #define SECOND_H namespaceNS2 // 宣告名稱空間 NS2 { const double Gain = 2.6; struct Member { int IdNum; char Name[20]; double Profit; }; double Fnc(double); } #endif

  18. 範例程式 檔案 FncLib.cpp // FncLib.cpp #include "First.h" // 引入NS1的宣告 #include "Second.h"// 引入NS2的宣告 // 定義函數 NS1::Fnc() double NS1::Fnc(double x) {return x * NS1::Gain;} // 定義函數 NS2::Fnc() double NS2::Fnc(double x) {return x * NS2::Gain;}

  19. 範例程式 檔案 Array2Fnc.cpp // TestHead.cpp #include <iostream> using namespace std; #include "First.h" // 引入NS1的宣告 #include "Second.h"// 引入NS2的宣告 // ----主程式---------------------- int main() { NS1::Member Ma={"George Wang", 23246352}; NS2::Member Mb={34,"Peter White", 12.67};

  20. cout << "Name of Ma is: " << Ma.Name << endl; cout << "Name of Mb is: " << Mb.Name << endl;; cout << "NS1::Gain is: " << NS1::Gain << endl; cout << "NS2::Gain is: " << NS2::Gain << endl; cout << "NS1::Fnc(2.5) is: " << NS1::Fnc(2.5) << endl; cout << "NS2::Fnc(2.5) is: " << NS2::Fnc(2.5) << endl; return 0; }

  21. 操作結果

  22. 使用「using指令」以存取名稱空間的成員 • 為了避免在存取時使用諸如 double x = MyNamespace::Ratio; 的冗長成員名稱,可以在程式中加入「using 指令」 (using directive) 加以簡化。例如: using namespace MyNamespace; … double x = Ratio;

  23. using指令 • 如果曾經在程式中宣告了名稱空間MyNamespace,則上述using指令相當於在指令的地方加入了下列四個宣告敘述: const double Gain = 5.9; struct Member { char Name[20]; int Phone; }; double Fnc(double);

  24. 名稱空間成員的適用範圍 • 局部變數的優先權高於全域變數 (global variables) 和名稱空間成員。 • 如果using 指令或using 宣告寫在區塊之內,則其作用範圍就只有到那個區塊結尾的地方。

  25. 範例程式 檔案 Priority.cpp // Priority.cpp #include <iostream> using namespace std; namespaceNS// 宣告名稱空間 NS { int M = 10; // (1) float x =1.0, y = 2.0; // (2) char C = 'G'; // (3) } // ----主程式----------------------- int main() { NS::M = 6; // 更動(1)中的M

  26. { float y = 7.5; // (4)定義局部變數 y using namespaceNS;// using 指令 x = 5.6; // 更動(2) 中的 x cout << y; // 輸出(4) 中的 y (=7.5) } return 0; } // C = 'P'; 錯誤! 此處已無法取用 (3) 中的 C

  27. 實例介紹 • 為了方便對照,我們仍然保留16.2節問題內的First.h,FncLib.cpp和Test.cpp三個檔案的名稱: • 檔案First.h完全沒有改變,這個檔案宣告了名稱空間NS1。 • 在檔案FncLib.cpp中,我們只保留了函數NS1::Fnc() 的實作。 • 檔案Test.cpp也只包括了名稱空間NS1成員的使用。我們在這個檔案裹面示範了using指令的使用方式。 • 本程式在 DOS 下的編譯指令仍然為: bcc32 Test FncLib

  28. 範例程式 檔案 First.h // First.h #ifndef FIRST_H #define FIRST_H namespaceNS1 // 宣告名稱空間 NS1 { const double Gain = 5.9; struct Member { char Name[20]; int Phone; }; double Fnc(double); } #endif

  29. 範例程式 檔案 FncLib.cpp // FncLib.cpp #include "First.h" // 引入NS1的宣告 // 定義函數 NS1::Fnc() double NS1::Fnc(double x) {return x * NS1::Gain;}

  30. 範例程式 檔案 Array2Fnc.cpp // Test.cpp #include <iostream> using namespace std; #include "First.h" // 引入NS1的宣告 // 名稱空間 NS1的 using 指令 using namespaceNS1; // ----主程式----------------------- int main() { Member Ma={"George Wang", 23246352}; Member Mb={"Peter White", 34536767}; cout << "Name of Ma is " << Ma.Name << endl; cout << "Phone number of Mb is " << Mb.Phone << endl;; cout << "Gain is: " << Gain << endl; cout << "Fnc(2.5) is: " << Fnc(2.5) << endl; return 0; }

  31. 操作結果

  32. 使用「using宣告」(using declaration) • 「using宣告」可以選擇性的宣告名稱空間中的成員。例如: namespace NS1// 宣告名稱空間 NS1 { const double Gain = 5.9; double A, B, C; void Fnc1(double); void Fnc2(double); void Fnc3(double); void Fnc4(double); } namespace NS2// 宣告名稱空間 NS2 { const double Gain = 5.9; double A, B, E; void Fnc3(double); void Fnc4(double); void Fnc5(double); void Fnc6(double); }

  33. 使用「using宣告」 • 在NS1和NS2這兩個名稱空間中,變數A,B,和函數Fnc3()、Fnc4()同名。如果我們使用以下的using宣告: using NS1::A; using NS1::Fnc2; using NS1::Fnc3; using NS2::B; using NS1::Fnc5; 就可以選擇性的直接取用NS1中的變數A和函數Fnc2()、Fnc3(),以及NS2中的變數B和函數Fnc5()。

  34. 標準名稱空間 • C++ 的標準程式庫 (the C++ Standard Library) 將所有的程式庫成員都含括在簡稱為std的名稱空間裏面: 資料流程式庫 <fstream>, 輸出格式程式庫 <iomanip>,以及計時程式庫 <ctime> 等等都是。 • 能夠以單一名稱空間std涵蓋這些程式庫的原因,是因為名稱空間具有可以用累積的方式逐步加入的特性。

  35. 使用cout和endl的三種using敘述語法 (1/3) (1) 使用「using宣告」 #include <iostream> using std::cout; using std::endl; cout << 3.5 << endl;

  36. 使用cout和endl的三種using敘述語法 (2/3) (2) 使用「using指令」 #include <iostream> using namespace std; cout << 3.5 << endl;

  37. 使用cout和endl的三種using敘述語法 (3/3) (3) 使用資格修飾子 (qualifier) #include <iostream> std::cout << 3.5 << std::endl;

  38. 未命名的名稱空間 (unnamed namespace) • 用來限制全域變數 (global variables) 的範圍,使它只能在原有檔案內存取,無法跨越到另一個檔案來使用。例如: namespace { double GainL=5.6; // GainL 被限制 double FncA(double x) // FncA() 被限制 {return x*GainL;} } • 在其它檔案中,即使做了 extern int GainL; 的宣告也無法存取不具名的名稱空間中的任何成員。

  39. 範例程式 FncLib.cpp • 這個程式區分為FncLib.cpp和Check.cpp兩個檔案。 • 在檔案FncLib.cpp中,我們定義了函數FncB()。 • 在檔案Check.cpp中,我們以不具名的名稱空間限制了GainL和FncA() 只能在此檔案中使用。

  40. 範例程式 檔案 FncLib.cpp // FncLib.cpp // 定義函數 FncB() extern double GainG; // 取用Check.cpp 中的GainG // extern double GainL; // 錯誤! 此處已無法取用 GainL double FncB(double x) { double y = x*GainG; // double y = x*GainL // 錯誤!此處已無法取用 GainL return y; }

  41. 範例程式 檔案 Check.cpp // Check.cpp #include <iostream> using namespace std; namespace// 未命名的名稱空間 { double GainL=5.6; // GainL 被限制 double FncA(double x) // FncA() 被限制 {return x*GainL;} } double GainG = 3.8; // 全域常數 GainG double FncB(double); // FncB() 的原型 // ----主程式----------------------- int main() { cout << “FncA(5)是: ” << FncA(5) << endl; // 呼叫 FncA() cout << “FncB(5)是: ” << FncB(5) << endl; // 呼叫 FncB() return 0; }

  42. 操作結果

More Related