用继承的class实现继承的抽象(纯虚)class?

Fulfil inherited abstract (pure virtual) class with an inherited class?

我目前正在做一个小游戏引擎,刚遇到一个没想到的问题。

我有一个根 class,我引擎中的大多数 class 都来自 CPObjectCPObject 符合 CPObjectProtocol,抽象 class 定义了一些纯虚函数。

我创建了另一个协议 TextureProtocol 及其具体实现 SDLTexture,它也继承自 CPObject。到目前为止,一切正常,我可以创建 SDLTexture 的实例。但是,如果我让 TextureProtocol 继承自 CPObjectProtocol,clang 会告诉我无法创建抽象 class.

的实例

我假设 class 可以通过继承另一个 class 的实现来实现接口。我错了吗?

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

你的SDLTexture同时继承自CPObject和TextureProtocol,每一个都继承自CPObjectProtocol,所以你在每个SDLTexture中有两个不同的CPObjectProtocol副本,第二个副本有一个指向缺少那些纯虚拟实现的虚表的指针函数。

您应该阅读有关 "virtual inheritance" 的内容,它将允许您只有一个 CPObjectProtocol 副本。

由于 CPObjectProtocol 没有数据,只有方法,显然您的意图是在每个 SDLTexture 中只拥有它的一个副本。

我将简化示例来演示问题。你有:

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

您认为这是您的层次结构:

但实际上它看起来像这样:

这应该能说明问题。您的 D 有两个名为 foo 的纯虚函数(通过其 A 基的 both),其中只有一个具有覆盖(通过 B).通过 C 的路径没有覆盖 foo(),因此 D 仍然被认为是抽象的。

真正让你的结构变成菱形的方法是使用virtual inheritance:

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

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

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

这样只有一个base A class,所以只有一个virtual foo(),所以B中的覆盖就足够了。