今天跟大家聊聊我最近搞的这个`QueryInterface`,一开始我看到这个词的时候,也觉得挺唬人的,但真正上手之后,发现也没那么神秘,就是个接口查询的事儿。
事情是这样的,最近在做一个项目,里面涉及到各种组件之间的交互。一开始大家都是一股脑地往一个对象里塞接口,结果搞到后面,代码那叫一个乱,牵一发而动全身。后来我就寻思,这不行,得想个办法解耦才行。
于是我就开始研究`QueryInterface`。这玩意儿说白,就是让一个组件告诉你,它都实现哪些接口。如果它实现你想要的接口,那就给你返回一个指向该接口的指针,你就可以通过这个指针来调用接口里的方法。如果它没有实现你想要的接口,那就返回个空指针或者错误码,告诉你没这玩意儿。
我得明确一点,这个`QueryInterface` 实际上是从 COM (Component Object Model) 那里学来的概念。COM 里一个对象可以实现多个接口,`QueryInterface` 就是用来查询对象是否支持某个特定接口的。
我先从最简单的开始,写一个基类,里面就只有一个 `QueryInterface` 方法。这个方法接收一个接口 ID,然后根据这个 ID 来判断当前对象是否实现该接口。如果实现,就返回指向该接口的指针,否则返回空。
c++
class IUnknown {
public:
virtual void QueryInterface(int interfaceId) = 0;
然后,我又定义几个接口,每个接口都有自己的 ID。
c++
class IInterfaceA {
public:
virtual void MethodA() = 0;
class IInterfaceB {
public:
virtual void MethodB() = 0;
我写一个组件类,让它同时实现 `IInterfaceA` 和 `IInterfaceB`。在这个组件类的 `QueryInterface` 方法里,我根据传入的接口 ID 来判断返回哪个接口的指针。
c++
class MyComponent : public IUnknown, public IInterfaceA, public IInterfaceB {
public:
void QueryInterface(int interfaceId) override {
if (interfaceId == 1) { // IInterfaceA 的 ID
return static_cast
} else if (interfaceId == 2) { // IInterfaceB 的 ID
return static_cast
} else {
return nullptr;
void MethodA() override {
// 实现 MethodA
void MethodB() override {
// 实现 MethodB
我写一个简单的测试程序,来验证 `QueryInterface` 是否能正常工作。
c++
int main() {
MyComponent component = new MyComponent();
IInterfaceA interfaceA = static_cast
if (interfaceA != nullptr) {
interfaceA->MethodA();
IInterfaceB interfaceB = static_cast
if (interfaceB != nullptr) {
interfaceB->MethodB();
delete component;
return 0;
跑一下,没啥问题,`QueryInterface` 确实可以返回正确的接口指针。
这只是个最简单的例子。实际项目中,情况会更复杂一些。比如,接口 ID 的管理,错误处理,内存管理等等。
接口 ID 的管理: 我用的是简单的整数 ID,但实际项目中,最好用 GUID (Globally Unique Identifier) 来保证 ID 的唯一性。
错误处理: `QueryInterface` 返回空指针,只是简单地表示没有实现该接口。但实际项目中,最好返回一个错误码,来更详细地描述错误原因。
内存管理: `QueryInterface` 返回的指针,谁来负责释放?这需要仔细考虑,避免内存泄漏。
`QueryInterface` 还是挺有用的,它可以让组件之间的交互更加灵活和解耦。虽然一开始有点难理解,但只要多动手实践,就能掌握它的用法。
希望我的实践记录对大家有所帮助。有啥问题,欢迎留言讨论。