3

I am currently making a small game engine, and just faced a problem I didn't expect.

I have a root class that most classes in my engine derive from, CPObject. CPObject conforms to CPObjectProtocol, an abstract class defining a few pure virtual functions.

I created another protocol, TextureProtocol, and its concrete implementation, SDLTexture, that also inherits from CPObject. So far, everything works, and I can create instances of SDLTexture. However, if I make TextureProtocol inherit from CPObjectProtocol, clang tells me that I cannot create an instance of an abstract class.

I assumed that a class could fulfil an interface by 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's implementation?
class SDLTexture : public CPObject, public TextureProtocol {
public:
    SDLTexture() { _id = 0; }
    virtual ~SDLTexture { }

    // implementation of TextureProtocol
    virtual int getID() { return _id; }

private:
    int _id;
}
amyinorbit
  • 167
  • 2
  • 5
  • Please post some real code. I get dozens of syntax errors, and if I fix them all, the code compiles. In any case, you also need a virtual destructor in `CPObjectProtocol`. – Christian Hackl Jul 17 '15 at 12:56
  • A related question [C++ pure virtual multiple inheritance](http://stackoverflow.com/questions/25806410/c-pure-virtual-multiple-inheritance) – Bo Persson Jul 17 '15 at 12:59

2 Answers2

6

I'll simplify the example to demonstrate 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 really it looks like this:

enter image description here

That should illustrate the issue. Your D has two pure virtual functions named foo (via both of its A bases), only one of which has an override (via B). The path via C has no override of foo(), so D is still considered abstract.

The way to actually make your structure into a diamond is to use virtual inheritance:

struct B : virtual A {
    void foo() override { }  
};

struct C : virtual A {
    virtual void bar() = 0;    
};

struct D : B, C {
    void bar() override { }  
};

This way there is only one base A class, and so only one virtual foo(), so the override in B is sufficient.

Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977
3

You SDLTexture inherits from both CPObject and TextureProtocol, each of which inherits 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 implementation of those pure virtual functions.

You should read about "virtual inheritance" which will allow you to have only one copy of CPObjectProtocol.

Since CPObjectProtocol has no data, just methods, it was clearly your intent to have just one copy of it in each SDLTexture.

JSF
  • 5,281
  • 1
  • 13
  • 20