11

私はいくつかの(C ++)コードを調べていて、次のようなものを見つけました:

//Foo.cpp
namespace
{
    void SomeHelperFunctionA() {}
    void SomeHelperFunctionB() {}
    void SomeHelperFunctionC() {}

    //etc...    

    class SomeClass //<---
    {
        //Impl
    };
}

SomeHelperFunction[A-Z]その翻訳ユニットでのみ必要な関数なので、匿名である理由を理解していますnamespace。同様に、SomeClassもその翻訳ユニットでのみ必要ですが、グローバルクラス宣言がない場合は、名前の衝突なしに、異なる翻訳ユニットで同じ名前のクラスを作成できるという印象を受けました(たとえば、一般的に含まれるヘッダーファイル)。

また、この特定の変換ユニットには、同じ名前()のクラスを宣言する可能性のあるヘッダーは含まれていませSomeClass

それで、この情報を与えられて、誰かが元のプログラマーがこれをしたかもしれない理由にいくつかの光を当てることができますか?おそらく将来への予防策として?

正直なところ、匿名の名前空間で使用されるクラスはこれまで見たことがありません。

ありがとう!

4

5 に答える 5

7

匿名名前空間は、グローバルレベルで適用される場合、静的キーワードに似ています。

匿名の名前空間を使用すると、名前空間内で別のファイルから何も呼び出せなくなります。

匿名の名前空間を使用すると、現在のファイルのみに含まれる範囲を制限できます。

プログラマーは、名前の競合を避けるためにこれを行ったでしょう。リンク時にこのようにグローバル名が競合することはありません。

例:

ファイル:test.cpp

namespace 
{
  void A()
  {
  }
  void B()
  {
  }
  void C()
  {
  }
}

void CallABC()
{ 
  A();
  B();
  C();
}

ファイル:main.cpp

void CallABC();//You can use ABC from this file but not A, B and C

void A()
{
//Do something different
}

int main(int argc, char** argv)
{
  CallABC();
  A();//<--- calls the local file's A() not the other file. 
  return 0;
}

上記は正常にコンパイルされます。ただし、メインで関数を作成しようとするとCallABC()、リンクエラーが発生します。

このように、、および関数を個別に呼び出すことはできませんがA()B()それらC()すべてCallABC()を次々に呼び出す呼び出しを行うことができます。

CallABC()main.cpp内で前方宣言を行い、それを呼び出すことができます。ただし、リンクエラーが発生するため、main.cpp内でtest.cppのA()、B()、またはC()を前方宣言することはできません。

名前空間内にクラスがある理由については。これは、外部ファイルがこのクラスを使用していないことを確認するためです。.cpp内の何かが、おそらくそのクラスを使用しています。

于 2009-07-18T16:14:22.350 に答える
1

グローバルクラス宣言がなければ、名前の衝突なしに、異なる翻訳単位で同じ名前のクラスを持つことができるという印象を受けました

そうではありません。これらの「共通の」グローバル クラス定義はヘッダー ファイルにあることに注意してください。それらは文字通り含まれており、その共通のグローバル クラス定義をすべての翻訳単位にコピーします。複数の翻訳単位にまったく同じクラス定義を含める別の方法(マクロ展開など) を使用する場合も問題ありません。ただし、同じクラス名に対して異なる定義がある場合は、未定義の動作が発生する危険があります。運が良ければリンク失敗。

于 2009-07-20T10:58:13.663 に答える
1

誰かがこのコードをリンクし、同じ名前のクラスの定義が含まれていて、このファイルが他の実装の前にリンクされている場合、名前の競合が発生します。

于 2009-07-18T16:18:32.763 に答える
1

C++ ISO 標準 (セクション 2.3) には、The One Definition Ruleというルールがあります。

C++ ではコンパイルとリンクの関係が複雑であるため、これは単純なルールではありません。詳細のほとんどはここにあります

ただし、クラスのメンバーである関数には適用されます。これは、(リンク レベルでは) 長い名前を持つ単純な関数であるためです。

リンカは別の翻訳単位 (ソース ファイル) に現れるテンプレート クラスまたは関数の余分な定義を喜んで破棄するため、テンプレートには少し異なる方法で適用されます。これは、同じテンプレートの 2 つの異なる定義を提供すると、プログラムの動作が未定義になることを意味します (最良のシナリオ: 定義の 1 つが暗黙のうちに無作為に選択されます)。

于 2009-07-18T21:20:44.523 に答える