I am having a bit of a struggle with Microsoft Visual C++ 2015 and was able to replicate the issue with a small program. Given the following classes:
class BaseClass {
public:
BaseClass()
: mValue( 0 )
, mDirty( true )
{}
virtual ~BaseClass() {}
virtual int getValue() const { if( mDirty ) updateValue(); return mValue; }
protected:
virtual void updateValue() const = 0;
mutable bool mDirty;
mutable int mValue;
};
class DerivedClass : public BaseClass {
public:
DerivedClass() {}
protected:
void updateValue() const override
{
mValue++;
mDirty = false;
}
};
class Impersonator {
public:
Impersonator() {}
// conversion operator
operator DerivedClass() const
{
return DerivedClass();
}
// conversion method
DerivedClass toDerived() const
{
return DerivedClass();
}
};
I get a "pure virtual function call" error when I do the following:
void use( const BaseClass &inst )
{
// calls `getValue` which in turns calls the virtual function 'updateValue'
int value = inst.getValue();
}
int main()
{
// creates a temporary, then passes it by reference:
use( DerivedClass() ); // this works
// calls conversion operator to create object on stack, then passes it by reference:
DerivedClass i = Impersonator();
use( i ); // this works
// calls conversion method to create a temporary, then passes it by reference:
use( Impersonator().toDerived() ); // this works
// calls conversion operator to create a temporary, then passes it by reference:
Impersonator j = Impersonator();
use( j ); // causes a pure virtual function call error!
return 0;
}
Given that I can't change the void use(const BaseClass&)
function, can I change anything in the Impersonator
class to allow using the last call without generating a debug error?
The only way to mitigate the problem that I see is to add an operator const BaseClass&()
to Impersonator
and have it return a reference to DerivedClass
.
This will create a better conversion than the problematic/erroneous one the compiler is trying to use.
Naturally Impersonator
won't be able to return by value and create a temporary, so it will have to own a DerivedClass
object, or many objects, and dispose them somehow at an appropriate time. The simplest way that works for this demo program is to have it return a reference to its data member, but a real program may have to do something else.
class Impersonator {
public:
Impersonator() {}
// conversion operator
operator DerivedClass()
{
return d;
}
operator const BaseClass&()
{
return d;
}
private:
DerivedClass d;
};
This is a workaround. Create a wrapper for use
which accepts a const DerivedClass&
.
//I get a "pure virtual function call" error when I do the following :
void use(const BaseClass &inst)
{
// calls `getValue` which in turns calls the virtual function 'updateValue'
int value = inst.getValue();
}
void use(const DerivedClass &inst) {
use(static_cast<const BaseClass&>(inst));
}
The better match means the workaround wrapper will be selected, so a temporary of the correct type will be created, and a reference to that passed to the real use
implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With