Я хочу восстановить свой маленький 3d-движок, он очень маленький, поэтому я размещаю все файлы только в одном проекте.
Теперь я хочу восстановить его с помощью интерфейсов, чтобы я мог распределять разные модули по разным проектам и создавать их как dll.
когда я это делаю, я встречал много трудностей в базовом дизайне фреймворка.
Я хочу создать «Иерархию объектов» моего маленького движка, это было реализовано в предыдущей работе. например:
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, например:
template < typename TBase >
class TObject : public TBase
{
public:
virtual std::string GetName()
{
return m_strTest;
}
std::string m_strTest;
};
на основе этого TObject я могу реализовать 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, поэтому я должен изменить все «public xxx» на «virtual public xxx», это выглядит плохо.
Другой вопрос — CStaticMesh должен реализовывать все функции виртуального члена IStaticMesh, включая:
virtual void Draw() = 0;
virtual void BuildSomeMesh() = 0;
даже если в CMesh есть Draw, который является базовым вызовом 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;
}
};
это выглядит нормально, но как сделать CD3DSkeletalMesh? сделать TSkeletalMesh? ок, это безумие !!!
я думаю, это abime.
какая ошибка в этом дизайне? Как изменить дизайн идеи, чтобы избежать этой дилеммы? знаете ли вы идею, которая может сохранить иерархию наследования этих интерфейсов и легко реализовать?
если я использую много виртуального наследования, есть ли производительность?
Как вы упомянули, вы можете решить это с помощью виртуального наследования. Это создаст только один экземпляр класса интерфейса с множественным наследованием в иерархии.
Сначала интерфейсы:
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;
}
};
...
Для производительности последствия этого, посмотрите на этот вопрос.
Других решений пока нет …