0

This may already have an answer but I've not been able to find an exact case of what I'm attempting.

Suppose you have some generic variant-like class like so (irrelevant details omitted):

/* 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 */
}

For reasons specific to the project, it will be possible for such a variant type to refer to containers representing collections of this same variant type. That is, void* data within some Derived will store well-defined types, and those types may eventually lead back to another variation of Derived, and not knowing which ahead of time (it won't be possible during compilation) data must be void*.

It is acceptable for Base to keep track of T if necessary, and it can be set as an instance constant within Derived constructors.

What I'm not sure of is what happens after I create an instance of Derived, and store it (as a Base*) in a void*.

If I take the void* and cast it to Base* (as I won't be able to obtain type information out of runtime nor do I want to beyond what's happening here already), will calling functions like Read correctly use the Derived version despite the fact that the compiler is unable to determine what T is?

In code:

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

then later

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

I'm guessing (hoping) that the vtable depends only on the address (as void* or Base*), so this should work afaik and call the Derived<1>::Read() function despite the compiler being (probably) unable to determine the type ahead of time, but I'd like to be sure before building on top of this structure...

Xeren Narcy
  • 875
  • 5
  • 15
  • This all seems a bit strange. Why do you need to store a pointer to the derived part in the base class? Why store it as a `void*` rather than `Base*` or using the CRTP? – TartanLlama Jul 20 '15 at 07:38
  • yes, it calls `Derived::Read` https://ideone.com/UenJBB – m.s. Jul 20 '15 at 07:40
  • @TartanLlama it wont directly store it. Base::data = &Derived will never happen. However, Base::data _could_ store something like std::map, where Container manages access to Base. I've also considered CRTP but the problem becomes circular as I can't refer to Base without knowing which Derived to use. – Xeren Narcy Jul 20 '15 at 07:43
  • @XerenNarcy IMO you a looking at a design problem, not a code one. Why not try out codereview? – Captain Giraffe Jul 20 '15 at 07:46
  • @CaptainGiraffe might do later. for now it was a technical question regarding this specific approach. – Xeren Narcy Jul 20 '15 at 07:46
  • 1
    @CaptainGiraffe What code is there to review? [codereview.se] reviews real, working code, not generic code with `Derived` and `Base` and `...`. Please don't make random recommendations of Stack Exchange sites. – 200_success Jul 20 '15 at 08:00

1 Answers1

1

The pointer to vtable is essentially a hidden instance member in Base (in most implementations) so yes you'll be able to call correct overrides of Read and other virtual functions.

Alexander Balabin
  • 2,055
  • 11
  • 13
  • Ok, good to know, that's the impression I was getting with quick tests, but wasn't sure if I'd have to try out the full solution for there to be problems, thanks. – Xeren Narcy Jul 20 '15 at 07:46