c ++中的静态抽象方法

时间:2010-07-22 21:42:31

标签: c++ abstract

我有一个抽象基类

class IThingy
{
  virtual void method1() = 0;
  virtual void method2() = 0;
};

我想说 - “所有提供具体实例化的类都必须提供这些静态方法”

我很想做

class IThingy
{
  virtual void method1() = 0;
  virtual void method2() = 0;
  static virtual IThingy Factory() = 0;
};

我知道没有编译,无论如何它还不清楚如何使用它,即使它已编译。无论如何我只能做

Concrete::Factory(); // concrete is implementation of ITHingy

根本没有在基类中提及Factory。

但我觉得应该有某种方式来表达我希望实现注册的合同。

这有一个众所周知的习语吗?或者我只是把它放在评论中?也许我不应该试图强迫这个

编辑:当我输入问题时,我觉得自己模糊不清。我觉得应该有一些方法来表达它。伊戈尔给出了一个优雅的答案,但实际上它表明它确实无济于事。我最终还是要做

   IThingy *p;
    if(..)
       p = new Cl1();
    else if(..)
       p = new Cl2();
    else if(..)
       p = new Cl3();
    etc.

我想像c#,python或java这样的反射语言可以提供更好的解决方案

3 个答案:

答案 0 :(得分:33)

您遇到的问题部分与轻微违反单一责任原则有关。您试图通过界面强制执行对象创建。接口应该更纯粹,并且只包含与接口应该做的不可分割的方法。

相反,您可以从界面中获取创建(所需的virtual static方法)并将其放入工厂类中。

这是一个简单的工厂实现,它强制在派生类上使用工厂方法。

template <class TClass, class TInterface>
class Factory {
public:
    static TInterface* Create(){return TClass::CreateInternal();}
};

struct IThingy {
    virtual void Method1() = 0;
};

class Thingy : 
    public Factory<Thingy, IThingy>,
    public IThingy {
        //Note the private constructor, forces creation through a factory method
        Thingy(){}
public:
        virtual void Method1(){}
        //Actual factory method that performs work.
        static Thingy* CreateInternal() {return new Thingy();}
};

用法:

//Thingy thingy; //error C2248: 'Thingy::Thingy' : cannot access private member declared in class 'Thingy'

IThingy* ithingy = Thingy::Create(); //OK

通过从Factory<TClass, TInterface>中删除,派生类被编译器强制拥有CreateInternal方法。没有定义它会导致这样的错误:

  

错误C2039:'CreateInternal':不是   'Thingy'的成员

答案 1 :(得分:0)

没有确定的方法在C ++中规定这样的合同,因为也没有办法使用这种多态,因为行

Concrete::Factory()

总是一个静态编译时间的东西,也就是说,你不能写这行Concrete是一个未知的客户端提供的类。

您可以让客户实现这种“合同”,使其比不提供更方便。例如,您可以使用CRTP:

class IThingy {...};

template <class Derived>
class AThingy : public IThingy
{
public:
  AThingy() { &Derived::Factory; } // this will fail if there is no Derived::Factory
};

并告诉客户端派生自AThingy<their_class_name>(您可以通过构造函数可见性调整来强制执行此操作,但您无法确保客户端不会对their_class_name撒谎。)

或者您可以使用经典解决方案,创建工厂类的单独层次结构,并要求客户向您的API提供他们的ConcreteFactory对象。

答案 2 :(得分:0)

在C ++中,静态方法不能虚拟(或抽象)。

要执行您想要的操作,您可以拥有一个返回具体实例的IThingy::factory方法,但您需要以某种方式为工厂提供创建实例的方法。例如,定义一个方法签名,如IThing* (thingy_constructor*)(),并在IThingy中进行静态调用,您可以将此类函数传递给定义IThingy构建工厂实例的方式。然后,在依赖库或类中,您可以使用适当的函数调用此方法,该函数反过来说明如何正确构造实现您的接口的对象。

如果您没有调用工厂的“初始化程序”,则需要采取适当的措施,例如抛出异常。