Implement an inherited abstract (pure virtual) class with an inherited class?
I am currently building a small game engine and just ran into a problem that I did not expect.
I have a root class that most of the classes in my engine get from CPObject
. CPObject
corresponds CPObjectProtocol
to an abstract class that defines several pure virtual functions.
I created another protocol TextureProtocol
and its concrete implementation SDLTexture
that inherits from CPObject
. So far, everything works and I can create instances of SDLTexture. However, if I inherit TextureProtocol
from CPObjectProtocol
clang informs me that I cannot instantiate the abstract class.
I assumed that a class could execute an interface while inheriting from another class's implementation. Was I wrong?
// CPObject abstract interface/protocol
class CPObjectProtocol {
public:
virtual void retain() = 0;
virtual void release() = 0;
//more methods like this
};
// CPObject implementation.
class CPObject : public CPObjectProtocol {
public:
CPObject() { _retainCount = 0; }
virtual ~CPObject() { }
// implementation of CPObjectProtocol
virtual void retain() { _retain++; }
virtual void release() {
if(--_retainCount <= 0) {delete this;}
}
private:
int _retainCount;
};
// Texture absract interface/protocol
// inherits from CPObjectProtocol so that retain() and release()
// can be called on pointers to TextureProtocol (allowing for
// implementations to be swapped later)
class TextureProtocol : public CPObjectProtocol {
public:
virtual Color getColor() = 0;
};
// An implementation of TextureProtocol
// I assumed it would fulfil CPObjectProtocol by inheriting
// from CPObject implementation?
class SDLTexture : public CPObject, public TextureProtocol {
public:
SDLTexture() { _id = 0; }
virtual ~SDLTexture { }
// implementation of TextureProtocol
virtual int getID() { return _id; }
private:
int _id;
}
source to share
I'll simplify the example to illustrate the problem. You have:
struct A {
virtual void foo() = 0;
};
struct B : A {
void foo() override { }
};
struct C : A {
virtual void bar() = 0;
};
struct D : B, C {
void bar() override { }
};
You think this is your hierarchy:
But in reality it looks like this:
This should illustrate the problem. Yours D
has two pure virtual functions named foo
(via both of its bases A
), only one of which has an override (via B
). The path through C
does not override foo()
, so D
it is still considered abstract.
The way to turn your structure into a diamond is by using virtual
inheritance :
struct B : virtual A {
void foo() override { }
};
struct C : virtual A {
virtual void bar() = 0;
};
struct D : B, C {
void bar() override { }
};
Thus, there is only one base class A
, and therefore only one virtual one foo()
, so overriding in B
is sufficient.
source to share
You inherit SDLTexture from both CPObject and TextureProtocol, each inheriting from CPObjectProtocol, so you have two different copies of CPObjectProtocol in each SDLTexture, and the second copy has a pointer to a vtable that lacks the implementation of these pure virtual functions.
You should read about "virtual inheritance", which will only allow you to have one copy of the CPObjectProtocol.
Since CPObjectProtocol has no data, just no methods, it is obvious that you intend to have only one copy of this file in each SDLTexture.
source to share