標籤:

為什麼在 C++ 中,人們經常寫全命名空間,在其他語言卻不呢?

估計網上(比如知乎)有不低於 99% 的代碼寫的是

#include &
#include &
std::function& func;

而不是

#include &
#include &
using namespace std;
function& func;

或者

#include &
#include &
using std::function;
using std::string;
function& func;

而在 Java 里,可能有不低於 99.9% 的代碼都是:

import java.util.LinkedHashMap;
LinkedHashMap& strMap = new LinkedHashMap&<&>();

而不是:

java.util.LinkedHashMap& strMap = new java.util.LinkedHashMap&<&>();

或者更喪心病狂的:

java.util.LinkedHashMap& strMap = new java.util.LinkedHashMap&<&>();


這是因為 C++ 的模塊化做得太差了嗎?還是因為標準庫的命名太沒有辨識度(或者標準庫的市場推廣不力?),導致不加命名空間我們甚至第一時間都不能反應出來它指的是啥?


因為Java全局命名空間下只有其它命名空間和類,而C++名字空間下面有全局函數,全局變數,全局模板,類,枚舉,union

所以同樣的問題,在java下面你亂import,結果只可能是兩個不同包下的同名class衝突

而C++下面,可能是兩個不同命名空間的同名函數,枚舉,模板,變數......衝突,比java瞬間複雜2^5倍。

而且C++的重載是基於名字的,有可能你現在這個重載用的挺好的,using std過來一個同名的另一個函數,重載順序就變了,這都是潛在問題。


所以都不在頭文件裡面using namespace。不過cpp文件裡面經常using namespace的,因為一個正常尺寸的軟體,一個cpp用幾十個類的聲明信息家常便飯,不可能一個一個單獨using。


10月27日 補: 我是在黑。在黑C++。

++++

因為敲出 std:: 之後,我就靜等 IDE 智能提示……

那個提示時間大約需要耗費0.5秒,而我正好可以藉此時機,彈一下我的蘭花指,優雅地彈下煙灰。

我的 年輕的java 同事覺得我這動作夠味,他學去了,可惜IDE不給他這零點五秒,我驚訝地看到他嚎叫著去醫務室了。


在頭文件裡面 using 的話會污染 include 它的 cpp 所以一般不 using。cpp 裡面我還是經常 using 的。


比較一下:

std::function

java.util.function.Function

Java的包名實在太長了。。。根據域名倒置的包名約定,Java的包名很少有低於10個字元的,寫個那麼長的前綴,我累不累呀→_→


因為C++的namespace基本沒有組織啊

絕大多數東西都在std下,std::只是5個字元而已

(其實java也沒有什麼組織,只是包名不夠短)

你讓我把System.Collections.ObjectModel.ObservableCollection或者System.Threading.Tasks.TaskCanceledException寫完?


謝邀。

我個人一開始是在cppreference寫例子的時候養成加 std:: 的習慣,因為cppreference只有在寫了完整名稱的時候才能自動生成到相應條目的鏈接。

之後在其他討論中也使用全名,是為了防止歧義。C++標準庫的很多類型是可以不依賴黑科技就實現的,很多第三方庫也確實實現了與標準庫的一些類型對應的東西,但在細節上有所不同,例如有std::sort和thrust::sort、std::variant和boost::variant、std::future和folly::Future。為了明確一些描述只適用於標準庫的版本,才加上 std:: 以說明。我個人覺得這不是標準庫的名字沒有辨識度,相反,因為標準庫的命名沒有問題,第三方庫才會沿用。

在頭文件里使用 using 是不對的,這是由於語言本身的約束,這一點其他答主有解釋。

在實現文件使用 using 不算少見,當然也存在防止 ADL 而故意使用命名空間限定,或者因為標準庫組件用得不多所以不用 using 更省事的情況。


首先是為什麼不using namespace,這個主要是因為全拉進來在C++裡面是有名字空間污染問題的,因為C++的名字空間里洪水猛獸類函數枚舉全局變數各種模板各種using都有,放進來容易出事,為了保險起見,就辛苦點吧。

然後是為什麼可以寫全。原因就是突出一個短。一個std::可以解決各種標準庫的問題,而且因為沒有域名倒置的約定,自己寫的項目通常也不會把名字空間寫的很長。最後,如果別人寫的庫名字空間太長了?好辦,自己namespace vlns = very::long::namespace;削短即可。或者如果你只用其中的幾個類型,也可以用using給它們幾個短名字。


Java里import衝突,寫了衝突的類,都編譯不了吧?

但C++的話,衝突的東西他會盡量按照規則、優先順序去匹配,結果就是你可能根本不知道你用了哪個東西。

再者,考慮模板、2phase lookup之類的因素存在,一個namespace的引入可能會真實地影響其他namespace(存疑)……


難道不是因為C++的命名空間很短嗎?C++是std::xxx,而且C++很多縮寫,寫了也不礙多少事。而Java是java.xxx.xxx.xxxxx,而且都是完整的單詞,如果不import代碼會很難看。

而且C++頭文件using會傳染。


因為「std::」只有五個字元,很短。


頭文件,除非確信是給自己用的,加了 using namespace xxx 以後,你讓別人怎麼用?

比如人家項目里普遍用 boost::thread,所以在源文件里 using namespace::boost 了,然後你的頭文件里有個 using namespace std,好了,如果他 include 了你的頭文件,所有 unqualified 的 thread 都衝突了。

源文件里,看自己的喜好,使用 using namespace xxx,畢竟那是自己的東西。

再或者,如果你的類名足夠有特點(比如 QString、CString),連命名空間都可以不用。


using namespace寫在頭文件的全局作用域中會產生污染

所以所有頭文件中的聲明自然只可能寫全名了

模板或者inline實現的話

考慮在函數作用域內using namespace

寫給別人看的代碼片斷 為了明確當然也應該寫全名


這就好比為什麼明明有餐具,印度人還是在用手吃飯?

c++早期沒有namespace,後來引入了namespace之後很多人又不習慣用,導致各種混亂,所以就出現了這種奇葩的現象。如果大家都規範的是用namespace,那用using完全沒問題。

另外我還想吐槽的是為什麼java的namespace這麼長?普遍要搞4、5層的深度?


因為其他語言很少有C艹這樣喪心病狂的跨名稱空間重載,import的時候大部分也不會import被import模塊import的東西


頭文件裡面的規矩是要寫全的,因為怕污染包含文件的其它部分的代碼

但是真實原因是因為C++用戶不嫌麻煩啊,真的,嫌麻煩的人沒法用C++的。用C++的人的心理活動是,「只要能保留理論上最高的Micro-Manage能力,讓幹什麼都行」


C++頭文件有副作用,using namespace之後導致包含這個頭文件的其他文件也using了。


我寫C#代碼的話,是習慣寫命名空間全名的,因為我代碼水平低,隨時到處複製粘貼代碼。如果不寫全的話,一段代碼複製到別的地方之後,很可能會報錯。


c#裡面也要啊,全局名字污染很噁心的


不僅防污染、命名衝突,還能明確類型所屬「模塊」翻閱代碼時一目了然。且配合ide智能提示寫起來也舒服。

c++ framework大都為了審美統一(迎合std)基本都是小寫類名、函數名,前面不加命名空間::實在是看著頭疼。


Java一個import引入的東西更少,絕大部分時候只有一個類,而且包名很長。Cpp引入的東西太多,以std為甚。況且std這個名字也比較短。


Java有自動導入

C++不知道有沒有,可能有吧

Java類型明確,我看到String不用想也能知道是java.lang裡面的

C++太亂,遇到String,IDE都不知道這玩意是哪個地方定義的,要麼找不到定義,要麼出來好幾個定義 我用的source insight , vs可能更牛逼點吧


樓上, @孫明琦   說的很好,

這裡簡單說下,因為java的import是點到為止的,

import的作用僅僅是告訴編譯器,本java文件裡面,如果有interface、class找不到,從上面import的類、package裡面去找。

當你在當前類,import一個類,它的import是不會影響到你當前類的。

而c++的include, 可以循環嵌套,互相拷貝,收到影響的。

因此, 你不知道一個include裡面拷貝了多少各種東西來的,全局的類、變數、模板、枚舉.... 默然using 的話,在頭文件裡面using會影響到引用該頭文件的.cpp文件,所以一般不在頭文件using, 在.cpp裡面using。更多時候為了避免using帶來的出錯、引用多餘的,就寫全命名空間。

其實問題點就在這裡,cpp的include會互相拷貝,應用,作用在每個.cpp上。如果亂include、亂using, 這個很容易引起問題的。而且cpp的include一個頭文件後,還是需要using命名空間,個人還是覺得java的import只作用當前類、且分package的概念,真的很贊。看著繁瑣,其實是最簡潔的。


推薦閱讀:

既然編譯器可以判斷一個函數是否適合 inline,那還有必要自己加 inline 關鍵字嗎?
Windows 下最佳的 C++ 開發的 IDE 是什麼?
如何定義這種二維點的小於運算?
C++ 這門語言的優點體現在哪裡?
最近看到陳碩的一本書提了一個問題,「編譯器如何處理inline函數中的static變數?」

TAG:Java | C | C# |