我有一个模板类,它通过获取两个参数,一个整数和该类的前一个实例来构造。我希望能够在容器中存储这些类的实例,这就是为什么我从基类继承它(请忽略非智能指针):
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*
到derived<D>*
的转换,所以很遗憾无法编译(除非我使用static_cast)。有没有办法达到我的需要?提前谢谢!
答案 0 :(得分: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。我们可能想要摆脱所有这些*
,并且还要使每辆车“取得其内部汽车的所有权”(并且也负责删除它)。我们可以使用标准库的std::unique_ptr
来表示“所有权”这一概念(另请参阅How do I pass a unique_ptr argument to a constructor or a function?)......但实际上,我们所拥有的只是一个单链表{ {1}} s,这是STL免费提供给我们的东西:
ClownCar
所以我认为真正的问题是,你想要完成什么?
答案 1 :(得分:2)
David Nehme在评论中链接到的curiously recurring template pattern可能会做您正在寻找的内容。它不应该阻止您将派生类的对象存储在同一个容器中。看起来你正在实现一个双向链表,并自动创建给定的下一个项。 (这会使列表从该元素无效到结尾,除非它是尾部。)
我相信(我还没有尝试过)你应该在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()
是私有的或受保护的,则类必须是{{ 1}} S上。
使用friend
应该意味着您毕竟不需要CRTP,但是您必须检查每个强制转换,以确保它转换为正确的类型。