我试图将接口指针放在不同类型的着色器中,如下所示:
std::vector<ID3D11DeviceChild*> shaders;
ID3D11VertexShader* VS;
// ... instantiate and init VS
shaders.push_back(static_cast<ID3D11DeviceChild*>(VS));
// and when VS is needed again:
ID3D11VertexShader* VS = static_cast<ID3D11VertexShader*>(shaders[i]);
// use VS here
我的问题是这种类型转换COM接口的方法是否安全。我知道它适用于普通的多态类层次结构,但我不确定COM。
答案 0 :(得分:2)
首先,我建议在std::vector
之类的STL容器中存储智能指针而不是 raw拥有指针,例如
std::vector<CComPtr<ID3D11DeviceChild>> shaders;
在STL容器中使用原始拥有指针是泄漏源,潜在错误和异常不安全代码(观察原始指针很好)。
要从ID3D11DeviceChild*
转发到ID3D11VertexShader*
,请考虑使用QueryInterface()
(再次使用ATL智能指针,如CComPtr
简化代码):
CComPtr<ID3D11VertexShader> spVertexShader;
HRESULT hr = (shaders[i])->QueryInterface(IID_PPV_ARGS(&spVertexShader));
if (FAILED(hr))
...
<强> PS 强>
除非我遗漏了某些内容,因为ID3D11VertexShader
是ID3D11DeviceChild
的派生类,因此您不需要static_cast
:
shaders.push_back(static_cast<ID3D11DeviceChild*>(VS));
这应该没问题:
shaders.push_back(VS);
关于CAdapt
请注意,您可能需要CAdapt
使用std::vector
:
std::vector<CAdapt<CComPtr<ID3D11DeviceChild>>> shaders;
符合要求的C ++ 11 STL实现不需要CAdapt
,但我认为至少需要VS2008和VS2010。
我不确定更多现代版本的Visual Studio,但它似乎已经修复了,例如:
您可能希望阅读this Visual C++ blog post中标题为“抵制重载地址的操作符”的段落。
答案 1 :(得分:1)
ID3D11VertexShader
继承自ID3D11DeviceChild
,因此您甚至无需使用static_cast<ID3D11DeviceChild*>
将其推送到矢量。向下转换矢量元素到shader的更安全的方法是使用QueryInterface
:
CComPtr<ID3D11VertexShader> vs;
if (S_OK == shaders[i]->QueryInterface(IID_ID3D11VertexShader,
reinterpret_cast<void**>(&vs)))
{
// Use vs here
}
答案 2 :(得分:1)
只要您绝对确定,该向量只包含ID3D11VertexShader
,这是安全的,在这种情况下,您应该只使用它而不是ID3D11DeviceChild
。
如果您希望向量包含混合的接口指针,每个接口指针都有共同的祖先ID3D11DeviceChild
,那么最好依赖于QueryInterface
,以便存储到向量中并从向量中检索。
请记住,正确的代码优于快速代码,至少在开始时是这样。
当您分析时,如果,并且只有当您发现QI
是瓶颈时,那么您应该对此做些什么,但我建议您使用结构矢量它有一个指向ID3D11DeviceChild
的指针和一个接口标识符(IID),因此您可以在运行时检查您存储的接口指针类型:
struct DeviceChildPtr {
ID3D11DeviceChild *ptr;
REFIID riid;
};
std::vector<DeviceChildPtr> shaders;
// ... instantiate, initialize ...
DeviceChildPtr shader;
shader.ptr = static_cast<ID3D11DeviceChild*>(VS);
shader.iid = IID_ID3D11VertexShader;
shaders.push_back(static_cast<ID3D11DeviceChild*>(shader));
// ...
DeviceChildPtr shader = shaders[i];
// If you only ever use global IIDs, you may replace IsEqualIID with ==
// This is like a half-baked QueryInterface that only checks for a specific IID
if (IsEqualIID(shader.riid, IID_ID3D11VertexShader) {
ID3D11VertexShader* VS = static_cast<ID3D11VertexShader*>(shader.ptr);
// ... use ...
}
如果您经历过这条路径,请记住通过这种方式评论为什么(性能?)以及如何(通过运行时接口类型检查进行转换,安全性),而不是使用QueryInterface
。
我的猜测是,因为内部DX本身很可能会使用QueryInterface
,所以你不应该在这里找到瓶颈。