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;
}

      

+3


source to share


2 answers


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:

enter image description here

But in reality it looks like this:



enter image description here

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.

+5


source


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.

+3


source







All Articles