I have a controller function to take care of a number of objects whose specific classes are all derived from a pure virtual class.
class Abstract {
public:
virtual bool ReadyForWork() = 0;
virtual void DoWork() = 0;
};
Then I have the following:
class Specific : public virtual Abstract {
public:
bool ReadyForWork();
void DoWork();
};
The program creates an instance of Specific and assigns it to a void pointer in a chain.
vChain->Append(new Specific());
So far, so good. When the controller function kicks in and tries to access Specific's implementation of Abstract's virtual functions, though... eww.
The Specific object is there, I can access its contents by casting vChain's inner void* to Specific* and it all checks out, so bad memory isn't the issue. But the moment I cast the void* to Abstract*, the compiler loses the references to Specific's implementations, changing the function addresses to something entirely different from what was previously there - even though the pointer to the object itself is correct. Trying
// ...
Abstract *vWorkObj = (Abstract*)vChain->GetObj();
if (vWorkObj->ReadyForWork()) {
// ...
results in the following in my face:
Unhandled exception at 0x00000054 in Proj.exe:
0xC0000005: Access violation executing location 0x00000054.
But if I do this instead
// ...
Abstract *vWorkObj = (Specific*)vChain->GetObj();
if (vWorkObj->ReadyForWork()) {
// ...
it runs without a hiccup. Unfortunately, that doesn't help me much, as there are going to be multiple classes inheriting from Abstract.
I've tried something similar in a proof-of-concept project and it ran smoothly:
// ...
bool ReadyForWork(Abstract *pObjPtr) {
// ...
// ...
Specific *vObj = new Specific();
if (ReadyForWork(vObj)) {
// ...
Apparently the compiler doesn't like having to resolve inheriting classes at runtime. Is there a way to access an inheritor of an abstract class without explicitly telling the compiler which inheritor it is?
I suspect the casting to and from void* might be what's causing the compiler to lose its bearings, but it would save some hassle if the chain could be kept as generic as possible.
I'm using VS2013 Express for Windows Desktop. Thanks for your time.
The direct source of the problem is probably that you are using virtual inheritance, which complicates the layout of your class. It is usually only needed in complicated multiple inheritance scenarios, so maybe you wouldn't need it.
You want a pointer to the Abstract
subobject of a Specific
, which might not be the same memory address in your case. So if you store Abstract*
in vChain
, make sure you store the correct address by converting to a Abstract*
first:
vChain->Append(static_cast<Abstract*>(new Specific()));
Aside of that there is the question why vChain
contains void*
in the first place. If it would store Abstract*
no explicit casts would be necessary at all and the compiler would figure out the correct pointers automatically.
In general, when you convert a foo*
to void*
, it is only safe to convert back to the exact same type. There are cases where it works, there are cases where it happens to work, but in basically every case you are better off following this rule.
If you intend to convert your void*
later into an abstract*
, convert your foo*
to an abstract*
before converting it to a void*
. The best kind of such conversion is implicit.
abstract* p = new foo;
void* v = static_cast<void*>(p);
abstract*p2 = static_cast<abstract*>(v);
finally, if you know you are going to convert to an abstract*
later, consider changing the type of pointer you store meanwhile to an abstract*
.
User contributions licensed under CC BY-SA 3.0