4

假设您有一个类Dep树的基类。Dep* Dep::create()我希望每个叶类都实现一个虚拟方法。有什么办法可以强制执行吗?

注意:这里的问题是可能有中间类(比如)偶然class B : public A : public Dep实现了这个方法( ),或者因为他们认为它们是叶类,但实际上它们自己是子类。A::create

问题到此结束。

语境

如果你好奇我为什么需要这个;我有一个Master具有Dep未知具体类型的对象的类。如果Master重复,我需要提供一个匹配的Dep实例克隆。下一个最好的办法是虚拟构造函数,它正好引入了这个问题。

此外,我什至无法捕捉到这一点(除了可怕的崩溃),因为由于不明原因,比我有更多话要说的人已经dynamic_cast在这个项目中取缔了(也许这是一个很好的决定;但无论如何,这是一个完全不同的讨论)。

4

5 回答 5

4

C++ 无法阻止类从您的类继承,也无法使继承层次结构中的特定类实现方法。唯一的规则是,在特定类之上的继承层次结构中的某个位置(不一定在叶子中),所有虚函数都必须具有该类可实例化的实现。

例如,A可以继承Def并实现它的所有 [纯] 虚拟方法。那么如果B继承自A,它就不必实现任何东西。没有办法阻止这种情况发生。

所以答案是否定的,没有办法强制执行。

于 2011-09-02T20:17:42.230 回答
3

使用奇怪重复的模板乐趣,你可以实现非常相似的东西:

template<typename T>
class Cloneable : public T, public Dep
{
private:
    Cloneable<T>() : T() { }
public:
    static Cloneable<T>* Create() { return new Cloneable<T>(); }
    Cloneable<T>* clone() { return new Cloneable<T>(*this); }
};

不是从 via 派生Dep和实例化new MyType,而是使用Cloneable<MyType>::Create. 由于Cloneable<MyType>is 派生自MyType,因此您可以像使用 any 一样使用该实例MyType,但现在保证它具有Dep::clone.

此外,您Master不应该接受 type 的实例Dep,而是强制它是Cloneable<T>. (用一个简单的函数模板替换你的原始函数来强制执行这个。)这保证Dep了master内部的任何一个都具有正确实现的clone函数。

由于Cloneable<MyType>没有公共构造函数,它不能被继承,但是你的实际MyType可以像以前一样被进一步继承和使用。

于 2011-09-03T16:52:43.310 回答
2

TPTB 是取缔所有RTTI 还是仅取缔dynamic_cast<>()?如果您可以使用 RTTI,那么您可以强制方法的存在作为调用它的后置条件:

#include <typeinfo>
#include <cassert>
#include <iostream>
#include <stdexcept>

class Base {
protected:
  virtual Base* do_create() = 0;
  virtual ~Base() {}
public:
  Base* create() {
    Base *that = this->do_create();
    if( typeid(*this) != typeid(*that) ) {
      throw(std::logic_error(std::string() +
                             "Type: " +
                             typeid(*this).name() +
                             " != " +
                             typeid(*that).name()));
    }
    return that;
  }
};

class Derive1 : public Base {
protected:
  Base* do_create() { return new Derive1(*this); }
};

class Derive2 : public Derive1 {};

void f(Base*p) { std::cout << typeid(*p).name() << "\n"; }
int main() {
  Derive1 d1;
  Base *pD1 = d1.create(); // will succeed with correct semantics
  Derive2 d2;
  Base *pD2 = d2.create(); // will throw exception due to missing Derive2::do_create()
}
于 2011-09-02T20:47:53.370 回答
2

如果您控制基类AbstractDep,则可以强制使用类模板创建具体的叶类WithCloning。然后可以密封这片叶子,使其不能被继承。或者更准确地说,不能创建派生类的实例。

class AbstractDep
{
template< class Type > friend class WithCloning;
private:
    enum FooFoo {};
    virtual FooFoo toBeImplementedByLeafClass() = 0;

public:
    virtual AbstractDep* clone() const = 0;
};

template< class Type > class WithCloning;

class Sealed
{
template< class Type > friend class WithCloning;
private:
    Sealed() {}
};

template< class Type >
class WithCloning
    : public Type
    , public virtual Sealed
{
private:
    AbstractDep::FooFoo toBeImplementedByLeafClass()
    {
        return AbstractDep::FooFoo();
    }

public:
    virtual WithCloning* clone() const
    {
        return new WithCloning( *this );
    }
};

typedef WithCloning<AbstractDep>            Dep;


class AbstractDerivedDep
    : public AbstractDep
{
// AbstractDep::FooFoo toBeImplementedByLeafClass(); // !Not compile.
public:
};

typedef WithCloning<AbstractDerivedDep>     DDep;


struct Foo: Dep {};       // !Does not compile if instantiated.

int main()
{
    Dep     d;
    //Foo     f;
}

如果类需要的不仅仅是默认构造,那么大多数需要额外解决。

然后一种解决方案是从WithCloning构造函数转发一个参数包(我的博客上有一个示例 C++98 实现,C++0x 直接支持)。

总而言之,要实例化,类必须是WithCloning.

干杯&hth.,

于 2011-09-02T22:28:40.590 回答
0

当您说它们未知时,我认为它们仍然继承自公共基类/接口,对吗?

我能想到的唯一可以用来强制的就是在虚拟基类上添加

virtual Base* clone() {
    assert( 1==0 ); //needs to be overriden
}

因此您被迫覆盖,但这仅在运行时在尝试对缺少覆盖的类的实例调用克隆时检测到

即使您不允许使用 dynamic_cast 或 RTTI,您仍然可以在您的构建中为本地调试目的启用它,如果这将帮助您找到违规类的 typeid

听起来您对克隆模式很熟悉,但我会在这里悄悄发布,我们可以忘记它: http ://www.cplusplus.com/forum/articles/18757/

于 2011-09-02T20:20:13.213 回答