3

コンストラクターから仮想メソッドを呼び出したいという状況に直面しています。もちろん、これは不可能です (または、少なくとも目的の動作が得られません)。この回答では、回避策としてファクトリ メソッドを使用することが提案されています。私はこのようなものを書きました:

#include <iostream>
class Base {
    public:
        Base(){}
        ~Base(){}
    // private: ??
        virtual void afterConstruction()=0;
};
class Derived : public Base {
    public:
        Derived() : Base() {}
    //private: ??
        void afterConstruction(){std::cout<<"construct"<<std::endl;}
};
template <typename T> T MyFactory(){
    T t = T();
    T* p = &t;
    p->afterConstruction();
    return t;
}
int main(int argc, char** argv) {
    Derived d = MyFactory<Derived>();
    return 0;
}

テンプレートメソッドのパターンの一種です。各派生クラスは、構築方法をカスタマイズできます。ただし、この構造体全体が意味をなすのは、このクラスのユーザーがコンストラクターまたはafterConstruction()直接呼び出すことができない場合のみです。したがって、私はそれらの両方を非公開にしたいと思います。多分それはばかげた質問であり、私には明白なことがわからないだけです。友情などを使ってこれを達成できるかもしれませんが、これが最善の方法かどうかはわかりません. この 2 つのメソッドを非表示にして、ファクトリ メソッドを介したオブジェクトの作成のみを許可する、すてきでクリーンな方法は何ですか?

編集:Ka7Im1011 私が何を求めているのかがはっきりしていないことに気づきました。したがって、私は明確にしようとします:

他の人が派生しなければならない基本クラスを書きたいと思います。派生オブジェクトの構築には、基本クラスから除外したい非常に特殊なものが含まれます。Web で仮想コンストラクターを検索すると、上記の Q&A が見つかりました。ファクトリ アプローチがうまく機能すると思います。ただし、次のことを達成する方法がわかりません。

  • ファクトリから Derived のインスタンスを作成することだけが可能であるべきです。そうしないと、派生オブジェクトが一貫性のない状態で作成される可能性があります。(基本クラスだけではこれを強制することはできないと思いますが、Derived の各コーダーにコンストラクターを非公開/保護するように依頼するだけで十分です。)
  • 可能であれば、Derived は Base の純粋な仮想メソッドのみを実装する必要があります。これは、Derived を作成するのが非常に快適であるためです (IDE/コンパイラは、テンプレートのインターフェースなどの場合の冗長で時々不可解なエラー メッセージとは対照的に、実装する必要があるものを正確に通知します)。パラメータを実装する必要があります)
4

1 に答える 1

1

私はあなたの質問を正確に理解していませんが、これを探しているかもしれません.

#include <iostream>
#include <conio.h>

class Base
{
    virtual void afterConstruction() = 0;
};
class Derived : Base {
private:
    Derived() : Base() {}
public:
     void afterConstruction(){ std::cout << "construct" << std::endl; }
protected:
    static Derived GetInstance()
    {
        return Derived();
    }
};
template <class T> class MyFactory : T
{
public:
    static T GetInstance()
    {
        // Make sure every kind of T has protected GetInstance()
        T t = T::GetInstance();
        T* p = &t;
        p->afterConstruction();
        return t;
    }
};
int main(int argc, char** argv) {
    Derived d = MyFactory<Derived>::GetInstance();
    // Derived d1; // will cause error
    _getch();
    return 0;
}

編集された回答

#include <iostream>
#include <conio.h>

class Base
{
protected:
    Base() {  }
    virtual void afterConstruction() = 0;
    virtual Base* GetInstance() = 0;
};

class Derived : public Base {
protected:
    Derived() : Base() {  }
    void afterConstruction()
    {
        static bool bConstrucred = false;
        if (!bConstrucred)
        {
            std::cout << "construct" << std::endl;
            bConstrucred = true;
        }
    }
    Derived* GetInstance()
    {
        afterConstruction();
        return this;
    }
};

template <class T> class MyFactory : public T
{
public:
    T* GetInstance() { return T::GetInstance(); }
};

int main(int argc, char** argv) {
    Derived* d = MyFactory<Derived>().GetInstance();
    // Derived d1; // will cause error
    _getch();
    return 0;
}
于 2015-04-02T09:37:46.737 に答える