-2

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

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构造一个对象,即不重新分配内存。我在想这样的事情derived<D>construct_impl

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*to的转换derived<D>*(除非我使用 static_cast)。有什么办法可以达到我的需要吗?提前致谢!

4

2 回答 2

2

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

我相信(我还没有尝试过)你应该dynamic_cast<>在覆盖中测试 agetNext_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()是私有或受保护的,则这些类必须是friends。

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

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

于 2013-10-25T02:06:12.073 回答
2

您可能会误以为可以在 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++ish。我们可能想摆脱所有这些*s,并让每辆车“拥有”其内部车的所有权(并负责删除它)。我们可以使用标准库std::unique_ptr来表示“所有权”的概念(另请参阅如何将 unique_ptr 参数传递给构造函数或函数?)......但实际上,我们在这里所拥有的只是一个 - s 的链表ClownCar,这是 STL 免费提供给我们的东西:

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

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

于 2013-10-25T01:00:12.080 回答