6

pimplパターンを使用して、匿名名前空間で実装クラスを定義しようとしています。これは C++ で可能ですか? 私の失敗した試みを以下に説明します。

実装を名前付きの名前空間 (またはグローバルなもの) に移動せずにこれを修正することは可能ですか?

class MyCalculatorImplementation;

class MyCalculator
{
public:
    MyCalculator();
    int CalculateStuff(int);

private:
    MyCalculatorImplementation* pimpl;
};

namespace // If i omit the namespace, everything is OK
{
    class MyCalculatorImplementation
    {
    public:
        int Calculate(int input)
        {
            // Insert some complicated calculation here
        }

    private:
        int state[100];
    };
}

// error C2872: 'MyCalculatorImplementation' : ambiguous symbol
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}

int MyCalculator::CalculateStuff(int x)
{
    return pimpl->Calculate(x);
}
4

5 に答える 5

7

いいえ、ポインター型を使用する前に少なくとも型を宣言する必要があり、匿名の名前空間をヘッダーに配置しても実際には機能しません。しかし、とにかく、なぜあなたはそれをしたいのですか?本当に実装クラスを隠したい場合は、それをプライベート内部クラスにします。

// .hpp
struct Foo {
    Foo();
    // ...
private:
    struct FooImpl;
    boost::scoped_ptr<FooImpl> pimpl;
};

// .cpp
struct Foo::FooImpl {
    FooImpl();
    // ...
};

Foo::Foo() : pimpl(new FooImpl) { }
于 2011-04-21T14:50:59.883 に答える
3

はい。これには回避策があります。ヘッダー ファイルでポインターを void* として宣言し、実装ファイル内で再解釈キャストを使用します。

注:これが望ましい回避策であるかどうかは、まったく別の問題です。よく言われることですが、それは読者の練習問題として残しておきます。

以下のサンプル実装を参照してください。

class MyCalculator 
{
public:
    MyCalculator();
    int CalculateStuff(int);

private:
    void* pimpl;
};

namespace // If i omit the namespace, everything is OK
{
    class MyCalculatorImplementation
    {
    public:
        int Calculate(int input)
        {
            // Insert some complicated calculation here
        }

    private:
        int state[100];
    };
}

MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}

MyCalaculator::~MyCalaculator() 
{
    // don't forget to cast back for destruction!
    delete reinterpret_cast<MyCalculatorImplementation*>(pimpl);
}

int MyCalculator::CalculateStuff(int x)
{
    return reinterpret_cast<MyCalculatorImplementation*>(pimpl)->Calculate(x);
}
于 2011-07-11T14:54:44.600 に答える
1

いいえ、できません。Pimpl クラスを前方宣言する必要があります。

class MyCalculatorImplementation;

そしてそれはクラスを宣言します。その後、名前のない名前空間に定義を配置すると(anonymous namespace)::MyCalculatorImplementation、 とは関係のない別のクラスが作成されます::MyCalculatorImplementation

これが他の名前空間NSである場合は、前方宣言を修正して名前空間を含めることができます。

namespace NS {
    class MyCalculatorImplementation;
}

しかし、名前のない名前空間は魔法のように、そのヘッダーが他の翻訳単位に含まれると別のものに解決されます (そのヘッダーを別の翻訳単位に含めるときはいつでも新しいクラスを宣言することになります)。

ただし、ここでは匿名名前空間を使用する必要はありません。クラス宣言は public である可能性がありますが、実装ファイル内にある定義は、実装ファイル内のコードにのみ表示されます。

于 2011-04-21T14:55:16.793 に答える
1

ヘッダー ファイルで前方宣言されたクラス名が実際に必要であり、モジュール ファイルの匿名名前空間での実装が必要な場合は、宣言されたクラスをインターフェイスにします。

// header
class MyCalculatorInterface;

class MyCalculator{
   ...
   MyCalculatorInterface* pimpl;
};



//module
class MyCalculatorInterface{
public:
    virtual int Calculate(int) = 0;
};

int MyCalculator::CalculateStuff(int x)
{
    return pimpl->Calculate(x);
}

namespace {
    class MyCalculatorImplementation: public MyCalculatorInterface {
        ...
    };
}

// Only the ctor needs to know about MyCalculatorImplementation
// in order to make a new one.
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}
于 2011-04-21T15:26:46.997 に答える