はい、私は以前にダイヤモンドの継承を扱ったことがありますが、今回の私の問題はかなり独特のようでした。基本クラスとして機能するIShaderResourceというインターフェイスがあります。IVertexBufferと呼ばれるIShaderResourceから派生した別のインターフェイスがあります。次に、IShaderResourceから派生したD3D11ShaderResourceと呼ばれる基本インターフェイスの実装があります。その後、D3D11ShaderResourceを拡張し、IVertexBufferを実装するD3D11VertexBufferというオブジェクトがあります。これで、私の階層は次のようになります。
IShaderResource
/ \
/ \
IVertexBuffer D3D11ShaderResource
\ /
\ /
D3D11VertexBuffer
IShaderResourceには、純粋仮想関数が1つだけあります。これが通常のダイヤモンド継承と異なる部分は、IVertexBufferがその関数を実装していないことです。D3D11ShaderResourceがその機能を実装しているのに対し、それは抽象のままです。IShaderResourceを両方の派生クラスに仮想的に継承する場合でも、抽象関数が不足していると見なされます。システムを機能させるには、IVertexBufferをIShaderResourceから派生させる必要があります。実装は、実行時に動的にロードされるdllに含まれますが、プログラムの存続期間中はリンクされたままになります。したがって、dllから作成されたオブジェクトは、インターフェイスを介してどこからでもアクセスできますが、インターフェイスの背後では、プログラムの存続期間を通じて型が定義されます。例えば、d3d11ライブラリをロードして頂点バッファーを作成した場合、D3D11VertexBufferのインスタンスを指すIVertexBuffer ptrが返され、その後、他の実装された頂点バッファーの実装はできなくなります。これは、レンダラー内で、IShaderResourceをD3D11ShaderResourceにキャストして、それがどうなるかを十分に理解できることを意味します。(注*レンダラーの外部でこれを行うと、インターフェイスの目的が無効になります)
Rendererインターフェイスには、IVertexBufferのようなIShaderResourceを渡し、D3D11ShaderResource部分のみを介して基になるD3D11VertexBufferでアクションを実行したい関数がありますが、他の関数はIVertexBufferを受け取り、D3D11Vertexbufferでアクションを実行します。そのためには、IShaderResourceから派生して、D3D11ShaderResourceが完全なタイプのIShaderResourceであることを確認すると同時に、D3D11VertexBufferがIVertexBufferとD3D11ShaderResourceの両方から継承するようにする必要があります。
ここでは4000行のコードをプッシュしているので、問題のある抜粋を投稿します。
IShaderResource
class IShaderResource
{
public:
struct INIT_DESC
{
SYNC_USAGE usage;
};
public:
// virtual destructor for derived classes
virtual ~IShaderResource() {}
// the resource usage hint
virtual IRenderUtility::SYNC_USAGE GetUsageType() = 0;
};
IVertexBuffer
class IVertexBuffer :
public virtual IShaderResource
{
public:
struct INIT_DESC : public IShaderResource::INIT_DESC
{
const void * Data;
unsigned int ByteWidth;
unsigned int ByteStride;
};
public:
// virtual destructor for derived classes
virtual ~IVertexBuffer() {}
// the resource usage hint
virtual IRenderUtility::SYNC_USAGE GetUsageType() = 0;
};
D3D11ShaderResource
class D3D11RenderUtility::D3D11ShaderResource :
public virtual IRenderUtility::IShaderResource
{
public:
struct INIT_DESC
{
IRenderUtility::SYNC_USAGE usage;
ID3D11ShaderResourceView * resourceView;
};
public:
// default constructor
D3D11ShaderResource(INIT_DESC & desc) :
m_Usage(desc.usage),
m_ResourceView(desc.resourceView)
{}
// virtual destructor for derived classes
virtual ~D3D11ShaderResource() {}
// obtains the resource usage hint
IRenderUtility::SYNC_USAGE GetUsageType() {return m_Usage;}
// used to obtain the resource view of the object
ComPtr<ID3D11ShaderResourceView> GetResourceView() const {return m_ResourceView;}
protected:
IRenderUtility::SYNC_USAGE m_Usage;
ComPtr<ID3D11ShaderResourceView> m_ResourceView;
};
D3D11VertexBuffer
class D3D11RenderUtility::D3D11VertexBuffer :
public IRenderUtility::IVertexBuffer ,
public D3D11RenderUtility::D3D11ShaderResource
{
public:
struct INIT_DESC :
public D3D11ShaderResource::INIT_DESC
{
ID3D11Buffer * buf;
};
private:
// disable copy constructor
D3D11VertexBuffer(const D3D11VertexBuffer & buf);
// disable assignment operator
void operator=(const D3D11VertexBuffer & buf);
public:
// default constructor
D3D11VertexBuffer(INIT_DESC & desc) :
D3D11ShaderResource(desc),
m_Buffer(desc.buf)
{}
// virtual destructor for derived classes
virtual ~D3D11VertexBuffer() {}
// used to obtain the d3d11 vertex buffer pointer
ComPtr<ID3D11Buffer> GetBuffer() const {return m_Buffer;}
private:
ComPtr<ID3D11Buffer> m_Buffer;
};
IRenderUtility :: SYNC_USAGEは、フレームワークのさらに上の単純な列挙型であり、ComPtrは、comポインターを自動的に解放するために作成した小さなスマートラッパーです。それ以外は、残りはかなり明白です。
ところで、実際のエラーはこれです:
error C2259: 'SYNC::D3D11RenderUtility::D3D11VertexBuffer' : cannot instantiate abstract class
2> due to following members:
2> 'SYNC::IRenderUtility::SYNC_USAGE SYNC::IRenderUtility::IVertexBuffer::GetUsageType(void)' : is abstract
SYNCは、これらすべてが含まれる名前空間です。