【发布时间】:2011-07-08 05:06:39
【问题描述】:
我已经阅读了COM Programmer's Cookbook 中详细介绍的各种 COM 设计模式以及一些相关的 SO 线程,尤其是 the thread discussing composition vs. multiple inheritance。可能是因为我对 C++ 和 COM 都太陌生,我可能会错过各种来源中的观点,所以这是我用一句话表达的问题:
我可以扩展 MIDL 生成的接口供 DLL 内部使用吗?如果可以,鉴于 MIDL/COM 限制,我如何正确处理菱形问题/并行层次结构?
肮脏的细节......
希望能帮助其他人找出我的困惑所在,以下是我的假设:
1) COM 不支持虚拟继承,只允许通过接口进行多重继承。
2) 即使COM 看不到它,只要我不希望它被COM 直接暴露,使用不受支持的C++ 继承对我来说应该不是非法的。
3) 因为 MIDL 只允许接口的单一继承,如果我有一个并行层次结构,我需要为 coclass 聚合它们。
4) MIDL 似乎并没有声明 coclass 本身,所以我需要编写一个 .h 文件来声明实际的类,在那里,我可以根据需要进行扩展,以了解 COM 消费者不能使用它(这没关系)。
我想要做的是有一个处理大部分实现细节并将一些特定功能委托给子类的基础对象(我还没有决定它是否是抽象的,尽管我认为现在是抽象的) .客户端通常会使用子类。所以,
project.idl
import "oaidl.idl"
import "ocidl.idl"
[
object,
uuid(...),
dual,
oleautomation
]
interface IBase : IDispatch {
//stuff I want to show to COM
};
[
object,
uuid(...),
dual,
oleautomation
]
interface IChild1 : IBase {
//stuff (in addition to base) I want to show to COM
};
[
object,
uuid(...),
dual,
oleautomation
]
interface IChild2 : IBase {
//stuff (in addition to base) I want to show to COM
};
[
uuid(...),
version(...),
]
library myproject {
importlib("stdole32.tlb");
interface IBase;
interface IChild1;
interface IChild2;
[
uuid(...),
]
coclass Base {
[default]interface IBase;
interface IOle*; //include other IOle* interfaces required for the functionality
};
[
uuid(...),
]
coclass Child1 {
[default]interface IChild1;
interface IOle*; //those are delegated to the base members
};
[
uuid(...),
]
coclass Child2 {
[default]interface IChild2;
interface IOle*; //those are delegated to the base members
};
};
base.h
#include base_h.h //interfaces generated by MIDL
// I assume I need to re-include IOle* because IBase has no relationship
// and C++ wouldn't know that I want the object base to also have those
// interfaces...
class base : public IBase,
public IOle* {
//handle all IUnknown, IDispatch and other IOle* stuff here
//as well as the common implementations as appropriate
};
child1.h
#include base.h
//I'm not sure if I need to re-include the IOle* interfaces...
//I also assume that by inheriting base, child1 also inherits its interface
class Child1 : public Base,
public IChild1 {
//specific details only, let base handle everything else.
};
child2.h
#include base.h
//I'm not sure if I need to re-include the IOle* interfaces...
class Child2 : public Base,
public IChild2 {
//specific details only, let base handle everything else.
};
从概念上讲,创建一个新的 child* 对象总是意味着创建基础对象,因为需要基础来处理实现细节,所以我认为让基础处理 QueryInterface 和引用计数也是合适的,但是我对以下几点感到困惑:
1) 编译器抱怨由于并行层次结构导致成员不明确; IUnknown 从我的自定义界面和附加的 IOle* 界面重新实现了几次。文档表明,预计每个对象实际上只需要一个实现,但我不清楚我将如何解决编译器的问题,而且我觉得进行强制转换有点错误?我还想知道我是否应该虚拟继承所有接口,似乎对 C++ 有效,尽管 COM 不会有这样的理解,但它也不应该关心(?)。
2) 但是,如果我在 .h 文件中将所有继承的接口声明为虚拟接口,编译器就会抱怨当我尝试在 Base class.cpp 中实现 QueryInterface 时不允许继承的成员。我已经用谷歌搜索了那个错误,但不清楚它在这里试图告诉我什么。
编辑:我回答了我自己的问题。 Intel had documentation 这个错误我最初没有点击链接,假设它可能不适用于 Visual Studio。我希望我还是这样做了,但现在我明白了为什么我会收到这个错误,因为我试图在 Base:: 中而不是 IUnknown:: 或 IDispatch:: 中进行所有实现。现在,这引出了一个新问题,可以澄清我原来的主要问题——如果可能的话,我如何将实施从 IUnknown(和其他)推迟到 Base 并仅从 Base 工作?似乎如果我只使用 IUnknown::xxx,它就不能再访问 Base 的私有成员,这似乎是正常的事情,所以这可能不是我想要的。我尝试将除 base 自己的所有其他接口声明为虚拟接口,但这并没有真正采取。 (同样,我没有看到明显的解决方案可能是我的经验不足。)
3) Base 的 QueryInterface 不能将 base 强制转换为孩子,这是一个合理的抱怨,所以我认为无论如何我都必须为所有孩子重新实现 QI,但是一旦我确定请求的接口不是,我可以委托给 base 的 QI孩子的。奇怪的是,由于缺少 IUnknown 和 IDispatch 的成员,编译器坚持认为 child* 类是抽象的,但基础不是已经实现,因此孩子也应该拥有这些成员吗?
各种编译器错误让我担心我对语言和框架中的任何一个或两个都缺乏经验,这导致我对如何设计 COM 对象和继承层次结构以及实现细节做出有缺陷的假设,而我显然遗漏了一些东西这里。任何指点,甚至是一记耳光都将不胜感激。
谢谢!
【问题讨论】: