大一程設-下
東華大學
東華大學資管系
基本程式概念
資管經驗分享
相信寫過了這麼多程式之後,會發現我們的程式總是跟 main 綁再一起,透過學到了上一章的拆分檔案後,我們也學會了怎麼引入自己撰寫的 library,如果今天程式有非常多的 library,想必我們的專案會越來越大,而在專案擴充的過程當中,我們不免會遇到物件、函式可能會想取同名字的情況發生,但他們想觸發的事情可能或多或少會有不同,依靠一般的 function overloading 可能有時候沒有辦法完全的解決我們「撞名」的問題,甚至是想要取同名字的變數也有可能發生。
namespace 就是為了解決這樣撞名的問題而被設計出來的一種工具。
單純看這樣介紹或許沒辦法非常直白的了解,我們馬上開始吧!
我們假設以下一個情境來邊講述 namespace 吧!
假設今天有兩間學校,兩間學校都有非常多的學生,而針對學生呢,學校的資料庫會儲存以下的資料。
如果依照我們現在所學,我們可能很快會寫這樣的類別。
看起來非常正確簡單明瞭,然而經過探查我們發現,兩間學校針對資料變數型態的方式居然有些不一樣,但變數的名字居然都要求要一樣,那你可能會說,那我再宣告一個 class 就好了,這確實是一個非常有效的解法,那如果今天有第三個學校你可能也會選擇再加一個 class。
接著我們在擴充一下我們的需求,今天學校說除了記錄學生之外,希望我們也能夠幫教職員做資料的儲存,三間學校可能有三種教職員的儲存方式,你可能又會說,那建立三個類別分別給三間學校的教職員吧。
所以你可能會寫出 StudentA、EmployeeA、StudentB、EmployeeB、StudentC、EmployeeC,六個類別,別說了,看過去真的醜到開花。
今天在這樣的需求下我們可以知道,每間學校可能針對資料各有各的儲存方式,拆分成不同的類別確實也是正確的方式,基於這樣的基礎,我們其實能夠加上 namespace 來讓我們程式碼寫得看起來更好看一點。
你可以在 namespace 裡面寫所有你需要的東西。而定義在 namespace 裡面的東西,只隸屬於此命名空間,其他人如果要使用就必須取用他。
這樣一看就非常明瞭,只要是東華大學下的學生跟教職員,我們會如此的定義。也不用因為類別變多就取醜醜的什麼 ABC。而如果類別的細項有所不同也沒關係,名字也是可以取好好的。
那你可能會說,我們前面不是學了拆分檔案嗎,那我把不同的類別拆分到各自的檔案不就沒事了嗎?
非常好的解法,但如果今天同樣的一份程式需要 include 上面這兩間學校,在沒有 namespace 的支持下進行這樣類別的命名的時候,你會有兩個 Student 跟 Employee,你的程式碼會不知道要用哪一個類別。
你如果感到疑惑一定是上一篇筆記沒認真看
Orange
但如果今天我們有了 namespace 的支持,我們就可以明確地說,今天我要使用 NDHU 的 Stduent,或是我要使用 NTU 的 Employee。諸如此類。
我們馬上來使用命名空間吧。
在看例子之前,我們先來瞭解基本語法,如果 namespace 跟 main 放在同一個檔案裡面,不用 include 標頭檔,也不用寫 using。
你可以看到第 18 行,我們看到了久違的 ::
符號,還記得我們說過我們可以叫他 的
,所以不難理解,我們這邊實體化了一個 Student,隸屬於 NDHU,所以就是 NDHU 的 Student。
不用被混淆,NDHU::Student
就是物件宣告時的類別型態而已。剩下的取屬性,取用方法都跟我們過去學的一樣。
透過學了上一章的拆分檔案,我們來把 namespace 給拆分出去吧,都寫在 main.cpp 裡面太佔空間了。
我們假設現在有下面幾個重要的檔案。為了減少篇幅,全部的屬性我都設 public。
ndhu.h
ndhu.cpp
ntu.h
ntu.cpp
NTU 跟 NDHU 兩個最大的差異就是 NTU 的 Student 我加了一個 fly,以及兩者 phone 的基礎型態不同,學過繼承的你可能有另外的解決方式,所以我想說,解沒有絕對,完全看你怎麼組合你的工具!這邊只是為了仔細說明 namespace。
而你也可以看到在 ndhu.cpp
跟 ntu.cpp
我們寫了 NDHU::Stduent::play()
/ NTU::Student::play()
,主要就是在定義該類別底下的 function。
那如果你覺得這樣寫很麻煩,就要來使用 using 了。
相信 using namespace std
這句話困擾大家很長一段時間,我們先透過 ndhu 跟 ntu 來看看這奇怪的東西。
我們把 ndhu.cpp 修改一下。
我們在第三行加了 using namespace NDHU
,而在這個 namespace 底下有兩個類別,因此在這個 cpp 檔裡面,我們可以不用再寫那麼長的 NDHU::Student
這樣的前綴。
至於剩下的 include 就跟前面的筆記說的一模一樣,只是在過往學的東西再套上 namespace 這個新東西而已。
所以究竟 using namespace std
是甚麼,不難想像,有一個叫做 std 的命名空間,裡面有我們想要用的工具,所以我們需要 using 他,我們最常使用的 cin、cout 其實就被定義在裡面,所以如果今天我們沒有 using std 這個命名空間,我們的 cin、cout 該怎麼寫?
就是 std::cin
、std::cout
。
有忽然覺得茅塞頓開嗎?希望有拉XD
Orange
接著我們來看看最後的 main.cpp,假設我們想同時使用 NDHU 跟 NTU,按照前面學的,你可能會寫。
然而今天 NDHU 跟 NTU 這兩個命名空間都有 Student 跟 Employee,如果你直接宣告下面這樣會報錯。
他說 Student 是模糊的,NTU 也有一種 Student,代表現在電腦不知道該用哪一個了,所以這就是 namespace 好用的地方,能夠明確點出我是誰。
所以當今天類別撞名,就算你使用了 using 你還是得寫 NDHU::Student
/ NTU::Stduent
來明確讓編譯器知道誰是誰。
而透過上面的例子,你大概能夠在心裡構建出這樣一張圖。
兩個命名空間互不相干,非常簡潔明瞭,但你如果想要在 A 命名空間使用 B 命名空間的內容,其實也可以在 A 裡面透過 B::
去取用你要的東西。
今天如果需求更上升,需要劃分更明確的需求的時候,namespace 包著其他的 namespace 也是有可能的。
一個公司內部可能有多個部門,每個部門各司其職,份內事彼此互不相干,但如果有共同的東西想要被大家一起共用,你可以寫在大家都能夠存取到的地方。
巢狀並沒有限制幾層,想怎麼寫就怎麼寫,但要寫得有效率。
Orange
像上面這樣,Boss、age 跟兩個 function 是不論部門大家都可以用的,但如果今天 Engineering 需要用到 Finance 內的一些工具,就要在 Engineering 內寫 Finance::
,簡單明瞭。
這篇筆記主要是讓大家理解 namespace 的運作方式
namespace 讓我們能夠把程式碼區分得更明確,讓彼此不相干的功能不會互相影響,然而只單純使用 namespace 有時候不會完全的讓程式碼簡潔,必要的時候是要結合繼承、運算子多載、函式多載等我們過去學過的功能來讓它的效益最大化。
當然更複雜的還有範本(template)、多型(polymorphism),與此結合程式碼能夠更加完善。