簡體   English   中英

C++ 命名空間建議

[英]C++ namespaces advice

我只是在自學 C++ 命名空間(來自 C# 背景),我真的開始認為即使 C++ 比大多數其他語言做得更好,嵌套命名空間也不是其中之一!

我是否認為為了聲明一些嵌套的命名空間,我必須執行以下操作:

namespace tier1
{
    namespace tier2
    {
        namespace tier3
        {
            /* then start your normal code nesting */
        }
    }
}

與之相反:

namespace tier1::tier2::tier3
{
}

à la C#?

當我需要轉發聲明時,這變得更加瘋狂:

namespace tier1
{
    namespace tier2
    {
        namespace forward_declared_namespace
        {
            myType myVar; // forward declare
        }
        namespace tier3
        {
            /* then start your normal code nesting */
            class myClass
            {
                forward_declared_namespace::myType myMember;
            }
        }
    }
}

請記住,我開發的典型系統包括:

MyCompany::MySolution::MyProject::System::[PossibleSections]::Type

這就是為什么您不傾向於在 C++ 示例中看到大量使用名稱空間的原因嗎? 或者通常只有單個(非嵌套)命名空間?

更新

對於任何感興趣的人, 這就是我最終解決這個問題的方式。

C++ 命名空間並不是一種設計機制——它們只是為了防止名稱沖突。 在 99.99% 的情況下,您確實不想或不需要使用嵌套命名空間。

在 C++ 中正確使用命名空間的一個很好的例子是 C++ 標准庫。 這個相當大的庫中的所有內容都放在一個名為std 的命名空間中——沒有嘗試或需要將庫分解成(例如)一個 I/O 子命名空間、一個數學子命名空間、一個容器子命名空間等等。

在 C++ 中建模的基本工具是類(在某種程度上是模板),而不是命名空間。 如果你覺得需要嵌套,你應該考慮使用嵌套類,它比命名空間有以下優點:

  • 他們有方法
  • 他們可以控制訪問
  • 它們不能重新打開

考慮到這些之后,如果您仍然希望使用嵌套命名空間,那么就這樣做 - 以這種方式使用它們在技術上沒有任何問題。

C++ 命名空間比以前的產品有了很大的改進(即根本沒有命名空間)。 C# 命名空間擴展了這個概念並運行了它。 我建議您將命名空間保持在一個簡單的平面結構中。

編輯您是否建議由於我在此處概述的缺點?

簡單地說“是”。 C++ 命名空間的設計目的不是像在 C# 中那樣幫助您划分邏輯和庫。

C++ 命名空間的目的是阻止 C 開發人員在使用兩個導出相同函數名稱的第三方庫時遇到名稱沖突的現實問題。 C 開發人員對此有各種解決方法,但這可能會很痛苦。

這個想法是 STL 等具有std::命名空間,“XYZ Corp”提供的庫將具有xyz::命名空間,您為“ABC corp”工作會將所有內容放在一個abc::命名空間中。

前向聲明時我所做的如下所示:

 namespace abc { namespace sub { namespace subsub { class MyClass; }}}

我的前向聲明被折疊成一行。 犧牲前向聲明的可讀性以換取其余代碼的可讀性。 對於定義,我也不使用縮進:

 namespace abc {
 namespace sub {
 namespace subsub {
 
 class MyClass 
 {
    public:
       MyClass();

       void normalIntendationsHere() const;
 };

 }
 }
 }

使用這種風格在開始時需要一些紀律,但對我來說這是最好的妥協。


從 C++17 開始,您可以使用問題作者提出的語法聲明命名空間。

namespace A::B::C { ... }

嵌套命名空間定義: namespace A::B::C { ... }等價於namespace A { namespace B { namespace C { ... } } }

https://en.cppreference.com/w/cpp/language/namespace

至少作為一個小幫助,在某些情況下你可以這樣做:

namespace foo = A::B::C::D;

然后將 A::B::C::D 引用為 foo。 但僅在某些情況下。

您可以跳過縮進。 我經常寫

namespace myLib { namespace details {

/* source code */

} } /* myLib::details */

C++ 源代碼最終被編譯成二進制,不像 C#/Java 停留在二進制中。 因此,namespace 只是為變量命名沖突提供了一個很好的解決方案。 它不適用於類層次結構。

我經常在代碼中保留一兩個命名空間級別。

首先,您可以避免名稱空間縮進,因為沒有理由這樣做。

在示例中使用命名空間不會顯示命名空間的威力。 而對我而言,他們的力量正在將領域區域一分為二。 將實用程序類與業務類分開。

只是不要在一個 .h 文件中混合不同的命名空間層次結構。 命名空間是對函數聲明接口的一種額外注釋。 查看命名空間和類名應該可以解釋很多東西。

namespace product
{
namespace DAO
{

class Entity
{
};

我發現你可以像這樣模仿 c# 命名空間;

namespace ABC_Maths{
    class POINT2{};
    class Complex{};
}

namespace ABC_Maths_Conversion{
    ABC_MATHS::Complex ComplexFromPOINT2(ABC_MATHS::POINT2)
    {return new ABC_MATHS::Complex();}

    ABC_MATHS::POINT4 POINT2FromComplex(ABC_MATHS::COMPLEX)
    {return new ABC_MATHS::POINT2();}
}

namespace ABC
{
}

但是代碼好像不是很整齊。 我希望能長期使用

最好將盡可能多的功能嵌套到類中,例如

namespace ABC{
    class Maths{
        public:
        class POINT2{};
        class Complex:POINT2{};
        class Conversion{
            public:
            static Maths.Complex ComplexFromPOINT2(MATHS.POINT2 p)
            {return new MATHS.Complex();}

            static MATHS.POINT2 POINT2FromComplex(MATHS.COMPLEX p)
            {return new ABC::MATHS.POINT2();}// Can reference via the namespace if needed
} /*end ABC namespace*/

這仍然有點啰嗦。 但確實感覺有點OO。

並聽到它似乎做得最好

namespace ABC
{
    class POINT2{};
    class Complex:POINT2{};
    Complex ComplexFromPOINT2(POINT2 p){return new Complex();}
    POINT2 POINT2FromComplex(Complex){return new POINT2();}
}

聽聽用法的樣子

int main()
{
    ABC_Maths::Complex p = ABC_Maths_Conversion::ComplexFromPOINT2(new ABC_MATHS::POINT2());

    // or THE CLASS WAY

    ABC.Maths.Complex p = ABC.Maths.Conversion.ComplexFromPOINT2(new ABC.Maths.POINT2());

    // or if in/using the ABC namespace

    Maths.Complex p = Maths.Conversion.ComplexFromPOINT2(new Maths.POINT2());

    // and in the final case

    ABC::Complex p = ABC::ComplexFromPOINT2(new ABC::POINT2());
}

找出為什么我從未像使用 c# 那樣使用 c++ 命名空間的原因很有趣。 它太冗長了,並且永遠不會像 c# 命名空間那樣工作。

C++ 中命名空間的最佳用途是停止說我的超級 cout 函數(每次調用時都會響起)與 std::cout 函數(這遠沒有那么令人印象深刻)混淆。

僅僅因為 c# 和 c++ 具有命名空間,並不意味着命名空間的含義相同。 它們不同但相似。 c# 命名空間的想法一定來自 c++ 命名空間。 有人一定已經看到了一個相似但不同的東西可以做什么,並且沒有足夠的想象力來給它自己的原始名稱,比如“ClassPath”,這更有意義,因為它是通往類的路徑而不是提供命名空間,其中每個空間可以具有相同的名稱

我希望這可以幫助別人

我忘了說所有這些方法都是有效的,適度使用前兩種可以合並到第三種中,以創建一個有意義的庫即(不是很好的例子)

_INT::POINT2{}

_DOUBLE::POINT2{}

所以你可以通過使用改變精度級別

#define PREC _DOUBLE 
// or #define PREC _INT 

然后為雙精度 POINT2 創建一個 PREC::POINT2 實例

用 c# 或 java 命名空間做這件事不是一件容易的事

顯然這只是一個例子。 想想用法如何閱讀。

您過度使用它們(並且您將一無所獲)。

我有時將深層命名空間聲明為單獨的標頭中的幾個宏

命名空間.h

#define NAMESPACE_TIER1_TIER2_TIER3 \
    namespace tier1 { \
    namespace tier2 { \
    namespace tier3 {

#define END_NAMESPACE_TIER1_TIER2_TIER3 }}}

要在其他地方使用它:

另一個文件.h

#include "./namespace.h"

NAMESPACE_TIER1_TIER2_TIER3;

/* Code here */

END_NAMESPACE_TIER1_TIER2_TIER3;

宏后面多余的分號是為了避免額外的縮進。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM