web-dev-qa-db-ja.com

C ++名前空間のアドバイス

私は自分自身にC++名前空間(C#のバックグラウンドから来ている)を教えているだけであり、C++が他のほとんどの言語よりも優れているすべてのことでさえ、ネストされた名前空間はそれらの1つではないと考え始めています!

ネストされた名前空間を宣言するには、次のことを行う必要があると思います。

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

とは対照的に:

namespace tier1::tier2::tier3
{
}

アラ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++の例で名前空間の使用をあまり見ない傾向がある理由ですか?または、通常、単一の(ネストされていない)名前空間のみですか?

[〜#〜] update [〜#〜]

興味のある方は、 これが私がやった方法です この問題に取り組んでいます。

72
Adam Naylor

C++名前空間は、設計メカニズムとして意図されたものではありませんでした-名前の衝突を防ぐためだけのものです。状況の99.99%で、ネストされた名前空間を使用する必要はまったくありません。

C++での名前空間の正しい使用の良い例は、C++標準ライブラリです。この非常に大きなライブラリのすべてがstdと呼ばれる単一の名前空間に配置されます-ライブラリを(たとえば)I/Oサブ名前空間、数学サブ-名前空間、コンテナのサブ名前空間など。

C++でのモデリングの基本的なツールは、名前空間ではなくクラス(およびある程度テンプレート)です。ネストの必要性を感じる場合は、ネストされたクラスの使用を検討する必要があります。これには、名前空間よりも次の利点があります。

  • 彼らには方法があります
  • アクセスを制御できます
  • 彼らは再び開くことはできません

これらを考慮して、ネストされた名前空間をどうしても使用したい場合は、そうしてください-この方法でそれらを使用することは技術的に間違っていません。

108
anon

C++名前空間は、以前の製品よりも大幅に改善されました(つまり、名前空間はまったくありません)。 C#名前空間は概念を拡張し、それを実行しました。名前空間をシンプルでフラットな構造に保つことをお勧めします。

[〜#〜] edit [〜#〜]ここで概要を説明した短所のためにアドバイスしますか?

単に「はい」。 C++名前空間は、C#のようにロジックとライブラリを分割するのに役立つようには設計されていません。

C++名前空間の目的は、同じ関数名をエクスポートする2つのサードパーティライブラリを使用するときに名前の衝突が発生するC開発者が遭遇する現実の問題を止めることです。 C開発者にはさまざまな回避策がありましたが、深刻な痛みになる可能性があります。

アイデアは、STLなどにstd::名前空間、「XYZ Corp」が提供するライブラリにはxyz::名前空間、「ABC corp」で作業している場合、単一のものにallを入れますabc::名前空間。

23
Binary Worrier

前方宣言が次のようになったときに私がすること:

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

私の前方宣言は1行にまとめられています。前方宣言の読みやすさは、残りのコードの読みやすさと引き換えに犠牲になります。また、定義にはインデントも使用しません:

 namespace abc {
 namespace sub {
 namespace subsub {

 class MyClass 
 {
    public:
       MyClass();

       void normalIntendationsHere() const;
 };

 }
 }
 }

このスタイルを使用するには、最初は少し規律が必要ですが、私にとっては最高の妥協です。

17
doc

少なくとも小さな助けとして、場合によってはこれを行うことができます:

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

そして、A :: B :: C :: Dをfooとして参照します。しかし、場合によってのみ。

8
Bill Lynch

インデントをスキップできます。私はよく書く

namespace myLib { namespace details {

/* source code */

} } /* myLib::details */

C#/ Javaはバイナリのままなので、C++ソースコードは最終的にバイナリにコンパイルされます。したがって、名前空間は、変数の名前の競合に対する優れたソリューションを提供するだけです。クラス階層用ではありません。

コードには、1つまたは2つの名前空間レベルを保持することがよくあります。

6
cuteCAT

まず、名前空間のインデントを避けることができます。理由はないからです。

例で名前空間を使用しても、名前空間の能力はわかりません。そして、私にとっての彼らの力は、ドメイン領域を互いに分割することです。ユーティリティクラスとビジネスクラスを分けます。

1つの.hファイルに異なる名前空間階層を混在させないでください。名前空間は、関数宣言のインターフェイスに対する一種の特別なコメントです。名前空間とクラス名を調べると、多くのことが説明できます。

namespace product
{
namespace DAO
{

class Entity
{
};
4
Mykola Golubyev

このような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*/

そして、それはまだ少し長めです。しかし、少しオブジェクト指向を感じます。

そして、それが最もよくできているように聞こえます

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++名前空間から生まれたに違いありません。誰かが似ているが異なることができることを見て、「クラスパス」のような独自の名前を付けるほど十分な想像力が残っていなかったに違いありません。各スペースが同じ名前を持つことができるスペースの命名

これが誰かの助けになることを願っています

これらの方法はすべて有効であり、最初の2つの適度な使用を3番目の方法に組み込んで、意味のあるライブラリを作成できることを忘れました。

_INT::POINT2{}

そして

_DOUBLE::POINT2{}

を使用して精度レベルを変更できます

#define PREC _DOUBLE 
// or #define PREC _INT 

次に、倍精度POINT2のPREC :: POINT2のインスタンスを作成します

これは、c#またはJava名前空間で行うのは簡単なことではありません

明らかにそれはほんの一例です。使用法の読み方を考えてください。

0
Ace_Of_John