5

抽象シングルトン クラスがあります。私の目標は、サブクラスが init() 関数を実装するだけで、それ以外は何も実装しないことです。これが私がしたことです:

template <typename T>
class Singleton
{
    public: 

        Singleton()
        {
            init();
        }

        static T& instance()
        {
            static T instance;
            return instance;
        }

    protected:
        virtual void init() = 0;   
};

class SubSingleton : public Singleton<SubSingleton>
{
    protected: 
        void init()
        {
            cout << "Init SubSingleton" << endl;
        }
};

init() は保護されており、public static 関数から呼び出すことができないため、これはコンパイルされません。この問題には 2 つの解決策があります。最初に init() 関数を公開できますが、この関数を公開したくありません。したがって、これは2番目のソリューションのみを残し、サブクラスを次のように変更します。

class SubSingleton : public Singleton<SubSingleton>
{
    friend class Singleton<SubSingleton>;

    protected:

        void init()
        {
            cout << "Init SubSingleton" << endl;
        }
};

これは完全に機能しますが、他のプログラマーが私のコードを拡張し、これを追加する必要があることを知らない可能性があるため、friend ステートメントは必要ありません。

フレンドステートメントなしでこれを実装する他の方法はありますか? アンドレイ・アレクサンドレスクの何か?

編集: init 関数は、instance() 関数の代わりにコンストラクターで呼び出されるようになりました。

EDIT2: 技術的な理由と互換性のために、init() 関数が必要であり、コンストラクターで初期化を行うことはできません。

キャストの解決策は機能しますが、コンストラクターから init() を呼び出すと、キャストが機能しなくなります。助言がありますか?

4

3 に答える 3

4

この init() はまったく必要ありません。ここで問題を起こすだけです。

template <typename T>
class Singleton
{
    public: 
        static T& instance()
        {
            static T instance;
            return instance;
        }
};

class SubSingleton : public Singleton<SubSingleton>
{
    public: 
        SubSingleton()
        {
            cout << "Init SubSingleton" << endl;
        }
};

このようにして、不要なものを削除するだけでなく、誰かが instance() を呼び出すたびに init() を呼び出すのを防ぎます...

于 2012-07-08T10:49:03.147 に答える
3

問題は、仮想機能を意図したとおりに使用していないことです。つまり、現在動作中のポリモーフィズムはありません。なんで?直接派生オブジェクトで init() を呼び出すためです。仮想である init() 関数の使用は、以下に示すように、基本クラスの参照または基本クラスのポインターで init() を呼び出す場合です。次に、呼び出しは基本クラスのスコープから行われ、instance() メソッドは基本クラスのメソッドであるため、そこから保護されたメソッドを呼び出すことはまったく問題ありません。

    static T& instance()
    {
        static T myInstance;
        Singleton<T>& t = myInstance;  // Just define a dummy reference here.
        t.init();
        return myInstance;
    }
于 2012-07-08T09:37:43.463 に答える
2

2種類のポリモルフィズムを組み合わせているようです。

1)「静的に」呼び出す場合SubSingleton::init()、つまりCRTPを使用する場合は、基本クラスで定義する必要はありませんが、基本クラスでアクセスできるようにする必要があります。

2)ただし、init()を仮想として定義する場合は、動的ポリモーフィズムを使用し、init()公開する必要はありません。

static T& instance() 
{ 
  static T instance; 
  static_cast<Singleton<T> &>(instance).init(); 
  return instance; 
} 
于 2012-07-08T08:58:42.333 に答える