如何"隐藏"使用工厂时的构造函数?

时间:2015-04-02 08:51:03

标签: c++ factory virtual-method template-method-pattern

我遇到了一种情况,我想从构造函数中调用一个虚方法。这当然是不可能的(或者至少它不会产生所需的行为)。 In this answer作为一种解决方法,建议使用工厂方法。我写了这样的话:

#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()时,这整个构造才有意义。因此,我希望他们两个都是私人的。也许这是一个愚蠢的问题,我只是没有看到明显的问题。也许我可以通过使用友谊或类似的东西来实现这一点,但我不确定这是否是最好的方法。什么是隐藏这两种方法并且只允许通过工厂方法创建对象的漂亮而干净的方法?

编辑: Ka7Im1011让我意识到我要求的并不是很清楚。因此,我将尝试澄清:

我想编写一个其他必须派生的基类。构造派生对象涉及到我想要保留在基类之外的非常具体的东西。当在网上搜索虚拟构造函数时,我发现了上面提到的q&amp; a,我认为工厂方法可以很好地工作。但是,我不确定如何实现以下目标:

  • 应该只能从工厂创建Derived实例。否则,可以在不一致状态下创建派生对象。 (我想在基类中我不能强制执行此操作,但要求每个编译器使用Derived使构造函数为private / protected就足够了。)
  • 如果可能的话,Derived应该只实现Base的纯虚方法,因为编写Derived非常舒服(IDE /编译器将准确地告诉必须实现什么,而不是详细的,有时是神秘的错误消息,例如界面必须实现模板参数)

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:0)

我不想破坏我的问题,因此我发布我的(部分)解决方案作为答案......

#include <cstdlib>
#include <iostream>
using namespace std;

class Base {
    public:
        ~Base(){}
        template <typename T> static T BaseFactory(){
            T t = T();
            Base* p = &t;
            p->afterConstruction();
            return t;
        } 
    protected:
        Base(){}
    private: 
        virtual void afterConstruction()=0;
};

class Derived : public Base {
    private:
        void afterConstruction(){std::cout<<"construct"<<std::endl;}
};
int main(int argc, char** argv) {
    Derived d = Base::BaseFactory<Derived>();
    return 0;
}

我仍然不知道如何使派生构造函数私有/受保护。我想避开朋友,因为(据我所知)每次添加派生类时我都要改变基础。