1

我想重建我的小型3D引擎,它非常小,因此我只將所有文件放在一個項目中。 現在,我想用接口重構它,所以我可以將不同的模塊分散到不同的項目中,並將它們構建爲一個dll。當我這樣做時,我在框架代碼的基本設計中遇到了很多困難。 我想設計一個我的小型引擎的「對象層次結構」,它是在以前的工作中實現的。例如:關於C++接口(純虛擬類)/多繼承/虛繼承的設計問題

Object 
Component 
SceneComponent 
StaticMeshComponent/SkelMeshComponent 
D3DSkelComponent 
... 

但它們直接實施。 現在,我想使用接口(純虛類),我設計的基本接口(用於測試):

#include <cstdio> 
#include <iostream> 
#include <string> 
using namespace std; 

class IObject 
{ 
public: 
    virtual std::string GetName() = 0; 
}; 

class IMesh : public IObject 
{ 
public: 
    virtual void Draw() = 0; 
}; 

class IStaticMesh : public IMesh 
{ 
public:  
    virtual void BuildSomeMesh() = 0; 
}; 

class ISkeletalMesh : public IMesh 
{ 
public: 
    virtual void PlayAnim(const std::string& strAnimName) = 0; 
}; 

class ID3DSkeletalMesh : public ISkeletalMesh 
{ 
public: 
    virtual void LoadD3D(const std::string& strD3D) = 0; 
}; 

看起來正常,但是當我試圖實現他們,我覺得這可能是一個不可能的使命。 首先,我可以寫一個模板類或正常類IObject提取,如:在此基礎上TObject的

template < typename TBase > 
class TObject : public TBase 
{ 
public: 
    virtual std::string GetName() 
    { 
     return m_strTest; 
    } 

    std::string m_strTest; 
}; 

,我可以實現CMesh:

class CMesh : public TObject<IMesh> 
{ 
public: 
    virtual void Draw() 
    { 
     cout<<"draw mesh" <<endl; 
    } 
}; 
    IMesh* pMesh = new CMesh(); // ok 
    IObject* pObj = pMesh;  // ok 

到目前爲止,它工作得很好。但如何實現CStaticMesh/CSkeletalMesh/CD3DSkeletalMesh? 它也許是這樣的:

class CStaticMesh : public CMesh, public IStaticMesh 
{ 
public: 

}; 

,但我有兩個IObject提取的基類,所以我必須改變所有的「公共XXX」到「虛擬公共XXX」,這很糟糕。 另一個問題是CStaticMesh必須實現IStaticMesh的所有虛擬成員函數,包括:

virtual void Draw() = 0; 
virtual void BuildSomeMesh() = 0; 

即使在CMesh平局是CStaticMesh的鹼基響應。 好吧,也許我需要一個TMesh:

template < typename TBase > 
class TMesh : public TObject<TBase> 
{ 
public: 
    virtual void Draw() 
    { 
     cout<<"draw mesh" <<endl; 
    } 
}; 

像這樣實施CStaticMesh:

class CStaticMesh : public TMesh<IStaticMesh> 
{ 
public: 
    virtual void BuildSomeMesh() 
    { 
     cout<<"Build Some Mesh!"<<endl; 
    } 
}; 

看起來不錯,但如何implment CD3DSkeletalMesh?做一個TSkeletalMesh?好的,這太瘋狂了!

我想,這是abime。 這是這個設計中的錯誤嗎?如何改變設計理念以避免這種困境?你知道一個可以保持這些接口的繼承層次並輕鬆實現的想法嗎?如果我使用許多虛擬繼承,有沒有什麼性能isuue?

回答

0

你可以用虛擬繼承來解決這個問題。這將只在層次結構中創建多個繼承的接口類的一個實例。

首先接口:

class IObject 
{ 
public: 
    virtual std::string GetName() = 0; 
}; 

class IMesh : virtual public IObject 
{ 
public: 
    virtual void Draw() = 0; 
}; 

class IStaticMesh : virtual public IMesh 
{ 
public:  
    virtual void BuildSomeMesh() = 0; 
}; 

class ISkeletalMesh : virtual public IMesh 
{ 
public: 
    virtual void PlayAnim(const std::string& strAnimName) = 0; 
}; 

class ID3DSkeletalMesh : virtual public ISkeletalMesh 
{ 
public: 
    virtual void LoadD3D(const std::string& strD3D) = 0; 
}; 

然後實現:

class CObject : virtual public IObject 
{ 
public: 
    std::string GetName() 
    { 
     return m_strTest; 
    } 

    std::string m_strTest; 
}; 

class CMesh : public CObject, virtual public IMesh 
{ 
public: 
    void Draw() 
    { 
     cout<<"draw mesh" <<endl; 
    } 
}; 

class CStaticMesh : public CMesh, virtual public IStaticMesh 
{ 
public: 
    void BuildSomeMesh() 
    { 
     cout<<"Build Some Mesh!"<<endl; 
    }  
}; 
... 

對於這對性能的影響,看this question