【问题标题】:static abstract methods in c++C++中的静态抽象方法
【发布时间】:2011-03-19 19:55:53
【问题描述】:

我有一个抽象基类

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

根本没有在基类中提及工厂。

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

有没有一个众所周知的成语?还是我只是把它放在 cmets 中?也许我不应该试图强迫这一点

编辑:当我输入问题时,我会感到自己含糊其辞。我只是觉得应该有某种方式来表达它。伊戈尔给出了一个优雅的答案,但实际上它表明它确实没有帮助。我最终还是不得不做

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

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

【问题讨论】:

  • 我不太确定你想要什么。您在寻找clone 方法吗?
  • 我想我并没有真正看到你需要这样的东西的真实情况?多态性只有在实际实例中才真正有意义。静态方法只是使用 MRO 的类名的常规函数​​。真的没有意义,在某些时候你必须知道 class::method 的名称,因为 c++ 是静态链接的。
  • 他似乎想指定子类有一个静态工厂方法。布莱恩,你应该把它移到答案空间。
  • 不完全是静态虚拟方法,但您可以尝试在调用受保护T::InternalMyMethod() 的抽象类中提供静态模板方法template<class T> static MyMethod()。如果调用了T:MyMethod<T>(),这将强制从您的抽象类继承的任何类实现static T::InternalMyMethod()

标签: c++ abstract


【解决方案1】:

在 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&lt;their_class_name&gt; 派生(您可以通过调整构造函数可见性来强制执行此操作,但不能确保客户端不会对their_class_name 撒谎)。

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

【讨论】:

  • "你不能在 Concrete 是一个未知的客户端提供的类的情况下编写这一行。"如果您有办法向工厂注册类型构造函数,则可以。我一直这样做,在我的消息传递层中只知道我的抽象类型,但利用工厂可以构造和返回在另一个库中定义的类型的实例。
  • 对不起,我应该说你不能直接从 IThingy 执行此操作,如果 Concrete 尚未定义,正如您所提到的。我的意思是说你需要向IThingy 提供一种方法来间接实例化Concrete
【解决方案2】:

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

相反,您可以从接口(所需的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&lt;TClass, TInterface&gt; 派生,编译器强制派生类具有 CreateInternal 方法。不定义它会导致这样的错误:

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

【讨论】:

    【解决方案3】:

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

    要做你想做的事,你可以有一个返回具体实例的IThingy::factory 方法,但你需要以某种方式为工厂提供一种创建实例的方法。例如,定义像IThing* (thingy_constructor*)() 这样的方法签名并在IThingy 中有一个静态调用,您可以将这样的函数传递给它定义IThingy 将如何构造工厂实例。然后,在依赖库或类中,您可以使用适当的函数调用此方法,而现在,您可以正确地构造实现您的接口的对象。

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

    【讨论】:

      猜你喜欢
      • 2012-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-05
      • 2021-10-16
      • 2011-09-26
      • 1970-01-01
      • 2010-10-23
      相关资源
      最近更新 更多