Search code examples
c++factoryvirtual-functionstemplate-method-pattern

How to "hide" constructor when using a factory?


I am faced with a situation, where I would like to call a virtual method from the constructor. This is of course not possible (or at least it does not produce the desired behavior). In this answer as a work-around it is proposed to use a factory method. I wrote something like this:

#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;
}

It is kind of a template method pattern. Each derived class can customize the way it is constructed. However, this whole construct only makes sense, when a user of this classes cannot call the constructor or the afterConstruction() directly. Thus I would like to have both of them private. Maybe it is a stupid question and I just do not see the obvious. Maybe I can achieve this by using friendship or something like that, but I am not sure if this is the best way. What is a nice and clean way to hide this two methods and only allowing to create object via the factory method?

EDIT: Ka7Im1011 Made me realize that it is not really clear what I am asking for. Thus I will try to clarify:

I want to write a base class that other will have to derive from. Constructing the derived objects involves quite specific stuff that I would like to keep out of the base class. When searching the web for virtual constructor I found the above mentioned q&a and I think a factory approach could work well. However, I am not sure how to achieve the following:

  • It should only be possible to create instances of Derived from the factory. Otherwise the derived object can be created in a non-consistent state. (I guess that in the base class alone I cannot enforce this, but asking each coder of a Derived to make the constructor private/protected would suffice.)
  • If possible, Derived should only implement pure virtual methods of the Base, because then writing a Derived is quite comfortable (IDEs/compilers will tell exactly what has to be implemented as opposed to verbose and sometimes cryptic error messages when e.g. an interface of a template parameter has to be implemented)

Solution

  • I Don't get your question exactly but, you might looking for this.

    #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;
    }
    

    Edited Answer

    #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;
    }