2015-07-20 86 views
0

这可能已经有答案,但我一直无法找到我正在尝试的确切案例。多态性:基于模板的派生类的非模板化基础,使用基指针

假设你有一些通用的变体样类,像这样(不相关的细节省略):

/* in hpp file */ 
struct Base { 
    void * data; 
    Base(); 
    virtual ~Base(); 
    // ... 
    virtual bool Read(...); 
} 

template <Some_Enum_Class T> 
struct Derived : Base { 
    // T-specific interface to deal with Base::data 
    bool Read(...); /* implementation in separate cpp file */ 
} 

有关针对该项目的原因,将有可能对这种变体类型来指代表示收藏容器这个相同的变体类型。也就是说,某些Derived中的void *数据将存储定义明确的类型,并且这些类型最终可能会导致Derived的另一个变体,并且不知道哪个提前(编译期间不可能)数据必须为void *。

如果需要,Base可以跟踪T,并且可以在Derived构造函数中将其设置为实例常量。

我不确定是什么发生后,我创建了一个Derived的实例,并将它(作为一个基*)存储在void *中。

如果我参加了无效*和它转换为基地*(我将无法获得类型信息了运行时的我也不想要超越什么的已经在这里发生),将调用的功能,如读正确使用尽管编译器无法确定T是什么,但派生的版本?

在代码:

Derived <1> * D = new Derived <1>; 
Base * B = (Base*) D; // c-cast for brevity unless this is part of the answer 
SendAsVoidPtr((void*) B); // at this point the type information is lost 

后来

void * arg = ReceiveVoidPtr(); 
Base * B = (Base*) arg; 
Base->Read(...); // which version does this call and why? 

我猜(希望)的虚函数表仅取决于地址(为void *或*基地),所以这应该工作afaik并调用Derived < 1> :: Read()函数尽管编译器正在(可能)无法提前确定类型,但我想确保在构建此结构之前...

+0

这一切似乎有点奇怪。为什么你需要在基类中存储一个指向派生部分的指针?为什么将它存储为'void *'而不是'Base *'或使用CRTP? – TartanLlama

+0

是的,它调用'Derived :: Read' https://ideone.com/UenJBB –

+0

@TartanLlama它不会直接存储它。 Base :: data =&Derived永远不会发生。但是,Base :: data _could_存储类似std :: map 的容器,其中Container管理对Base的访问。我也考虑过CRTP,但问题变成了循环,因为我不能在不知道派生使用的情况下引用Base。 –

回答

1

指向vtable的指针实质上是一个隐藏的实例成员,在Base(在大多数实现中),所以是的,您可以调用Read和其他虚拟函数的正确覆盖。

+0

好的,很高兴知道,这是我通过快速测试获得的印象,但不确定是否必须尝试完整的解决方案以解决问题,谢谢。 –