c++:通过基类接口构造派生对象

c++: Construct derived object via base class interface

本文关键字:派生 对象 接口 基类 c++      更新时间:2023-10-16

我有一个模板类,它是由两个参数构造的,一个整数和该类的前一个实例。我希望能够将这些类的实例存储在容器中,这就是为什么我让它从基类继承(请忽略非智能指针):

class base {
  virtual base* getNext(unsigned x) = 0;
};
template <class D>
class derived :
  public base {
  /* no memory allocation here, simply changes the data in next */
  void construct_impl(unsigned x, const derived<D>& previous, derived<D>& next); 

  derived();            /* default constructor */
  derived(unsigned x, const derived<D>& previous) { /* construct from previous object */
    allocate_memory_for_this();
    construct_impl(x, previous, *this);
  }
  base* getNext(unsigned x) {
    return new derived(x, *this);
  }
};

现在我想在 base 类中创建一个函数,它将以与construct_impl相同的方式构造一个derived<D>对象,即不重新分配内存。我在想这样的事情

class base {
  virtual base* getNext(unsigned x) = 0;
  virtual void  getNext_noalloc(unsigned x, base* already_allocated_derived_object) = 0;
}

它将像这样在派生类中被覆盖

void getNext_noalloc(unsigned x, base* already_allocated_derived_object) {
     construct_impl(x, *this, *already_allocated_derived_object);    
}

不幸的是,由于没有从base*derived<D>*的转换,因此无法编译(除非我使用static_cast)。有什么方法可以实现我需要的吗?提前感谢!

David Nehme 在评论中链接到的奇怪重复出现的模板模式可能会满足您的需求。它不应该阻止您将派生类的对象一起存储在同一个容器中。看起来您确实正在实现一个双向链表,并从给定的项自动创建下一个项目。(这将使从该元素到末尾的列表无效,除非它是尾部。

我相信(我还没有尝试过)你应该在覆盖中测试一个dynamic_cast<>,以便getNext_noalloc()测试next指针并调用匹配类的construct_impl()

// override in derived class
void getNext_noalloc(unsigned x, base* already_allocated_derived_object) {
  derived<D1>* p1 = dynamic_cast< derived<D1> >(already_allocated_derived_object);
  derived<D2>* p2 = dynamic_cast< derived<D2> >(already_allocated_derived_object);  
  if(p1 != NULL) {
    p1->construct_impl(x, *this, *p1); // 2nd parameter should take base type
  } else if(p2 != NULL) {
    p2->construct_impl(x, *this, *p2); // 2nd parameter should take base type
  }
}

这确实假定这两个类相互了解,因此您必须在声明类之后具有函数定义,如果construct_impl()是私有的或受保护的,则这些类必须friend

使用 dynamic_cast<>() 应该意味着您根本不需要 CRTP,但您必须检查每个强制转换以确保它转换为正确的类型。

将指针从基类型转换为子类型

你可能在误解C++

写作时感到困惑。
class ClownCar {
    unsigned int x;
    ClownCar inner_car;
};

但这是不可能的!sizeof(ClownCar)会是什么?它必须至少是 sizeof x + sizeof inner_car ;即sizeof(unsigned int) + sizeof(ClownCar);即,至少比自身大四个字节。

因此,类不能包含其自己的类的实例。 继承,无论是虚拟的还是其他的,在这里都无关紧要。那我们该怎么办呢?我们使用指针!

class ClownCar {
    unsigned int x;
    ClownCar *inner_car;
public:
    ClownCar() : x(0), inner_car(nullptr) {}
    ClownCar(unsigned int x, ClownCar *previous) : x(x), inner_car(previous) {}
    ClownCar *getNext(unsigned int x) {
        return new ClownCar(x, this);
    }
};
int main() {
    ClownCar inmost_car;
    ClownCar *car1 = inmost_car.getNext(42);
    ClownCar *car2 = car1.getNext(43);
    // ...
    delete car2;
    delete car1;
    // of course we don't delete inmost_car, since it lives on the stack
}

当然,这不是很C++。我们可能想摆脱所有这些*,并使每辆车"拥有"其内部汽车(并负责删除它)。我们可以使用标准库的std::unique_ptr来表示这种"所有权"的概念(另请参阅如何将unique_ptr参数传递给构造函数或函数?...但实际上,我们在这里得到的只是一个单链的ClownCar列表,这是STL免费提供给我们的:

struct ClownCar { unsigned int x; };
typedef std::list<ClownCar> ClownCarList;  // ta-da!

所以我认为真正的问题是,你想完成什么?