从基类初始化派生类

时间:2017-09-14 11:35:42

标签: c++ c++11 inheritance

我有一个类似于此的基类(但以下内容不能编译):

struct Base {
    virtual void foo()=0;

    virtual void init() 
    {
        using Derived = typename std::remove_reference<decltype(*this)>::type;
        *this = Derived(); // does not compile as Base is an abstract class
    }
};

Base有很多派生类,我想要做的是让它的所有派生类都有init()函数继承自Base并初始化自己(通过调用它们构造函数)。如果他们愿意,也允许他们覆盖init()

问题:

  1. 我知道它没有编译。如果我的Base不是抽象类,它会起作用吗?我想知道this指针是否会被解释为派生对象指针?

  2. 如何实现我的目标?

  3. ------------------------------- EDIT ------------ --------------------------

    澄清一下, init()函数实际上正在重置。它将每个派生对象重置为其默认状态。我希望它在具有这种默认行为的Base类中,并且如果派生类想要一些不同的reset(),它们可以自由地覆盖它。

3 个答案:

答案 0 :(得分:1)

一些用户在评论中提到了CRTP(奇怪的重复模板模式),没有显示具体的解决方案,所以这里有一个:

template <typename CRTP>
struct Base {
  virtual void foo()=0;

  virtual void init() 
  {
    static_cast<CRTP&>(*this) = CRTP{};
  }
};

struct Derived : public Base<Derived> {
  void foo() override {}
};

答案 1 :(得分:0)

您希望根据派生类的类型调用不同的函数。这是C ++中的多态。你可以随意使用嫌疑人:

  1. 有一个派生类覆盖的虚函数。即基于动态类型的派遣。
  2. 以某种方式查找静态类型并使用重载。即基于静态类型的派遣。
  3. CRTP是完成第二种方法的一种方法,让派生在继承点说出它的真实类型。

    一种非常 hacky 方式来完成第二种方式,很明显我推荐,但可能需要在一个功能失调的组织中,你没有其他的options:尝试dynamic_cast到派生类的各种选项。这可能很脆弱。但即使有一个重置功能,而不是使用构造和破坏是脆弱的。

    我建议重新评估您对重置成员功能的需求,询问您要尝试使用它完成的内容,并尽量不要降低工作产品的质量作为与您的组织交互的最终目的。 (我的意见。)

答案 2 :(得分:0)

选项1/2

也许你可以拥有一个执行你想要的行为的模板功能。然后可以从需要默认行为的每个派生类显式调用它。通过使函数为纯虚拟,您可以确保在每个派生类中实现它。创建一个智能指针类,它包含指向原始对象的指针,以及指向可以重新启动对象的函数的指针。

#define DEFAULTINIT \
virtual void init()\
{\
  DefaultBehavior(this);\
}\

template <typename T> void DefaultBehavior(T *x)
{
  *x = T();
}
struct Base {
    virtual void init() = 0;
};

struct Derived : virtual public Base
{
  DEFAULTINIT;
};

选项2/2

创建一个智能指针类,它包含指向原始对象的指针,以及指向可以重新启动对象的函数的指针。

struct Base {
  virtual ~Base()=0;
};

struct Derived : virtual public Base {
  int a = {};
};


template <typename T>
void default_initter(Base *b)
{
  T *d = dynamic_cast<T *>(b);
  *d = T();
}

typedef void (*initter)(Base *);
struct SmartPointer
{
  template <typename T>
  SmartPointer(T *d) : base(d), init(default_initter<T>) {};
  Base     * base;
  initter    init;
};

#include <iostream>

int main()
{
  Derived *d = new Derived();
  SmartPointer *sp = new SmartPointer(d);
  d->a = 5;
  std::cout << d->a << std::endl;
  sp->init(sp->base);
  std::cout << d->a << std::endl;
}