`
yanlijun250
  • 浏览: 783415 次
文章分类
社区版块
存档分类
最新评论

COM新手使用中一个易混淆的问题

 
阅读更多

其实也没什么,[don box]里面也提过这个问题,但是没有继续展开。

比如依照图形系统而言,一般封装时,接口可能会这么来设计:

interface IRenderObject{};

interface IRenderResource: public IRenderObject {};

interface IRenderTexture : public IRenderResource {};

实现时,所有的Render Object您都希望将其绑定到Device上,所以您一定会希望有一个Render Object的公共基类来管理链表之类的。于是就可能这样:

class MyObjectBase : public IRenderObject

{

MyObjectBase* m_pNext;

};

然后,为了记录资源的大小等信息,同理:

class MyResource

: public MyObjectBase

, public IRenderResource

{

uint m_unSize;

};

最后,实现了一个Texture:

class MyTexture

: public MyResource

, public IRenderTexture

{

GLuint m_hTexture;

};

ok,准备工作完成。


接下来,使用者拿到这个库后,可能会通过这个系统的一个Facade创建一个Texture资源:

IRenderTexture* texture = XXXXSystem()->CreateTexture();

然后,系统同时提供了一个资源管理的很好用,他想把这个用到资源管理系统中,于是他:

XXXXSystem()->ManagerResource( texture );


这里,因为ManagerResource也是在XXXXSystem里提供的,为了实现功能,系统的提供者可能会这么写:

voidManagerResource(IRenderResource* InResource)

{

MyResource* resource = static_cast<MyResource*>(InResource);

resource->InnerMethod();

resource->InlineMethod();


}

好了。

到这里,您可以先考虑一下,现在会发生虾米事情?




最好的情况——Crash。最差的情况——没有Crash,但是内部完全乱套了。

为什么?




我们看一下,这中间我们一直使用的是MyTexture的实例,它的内存布局如何呢?

4字节vtbl

4字节 void* m_pNext

4字节IRenderResource vtbl

4字节uint m_unSize

4字节IRenderTexture vtbl

4字节GLuint m_hTexture;

也就是说,

IRenderTexture* texture = XXXXSystem()->CreateTexture();

这句话返回的是这个实例从头往下的第16个字节(0起始)。

而且,最糟糕的是,在下面这一句中:

XXXXSystem()->ManagerResource( texture );

因为IRenderTexture同时“是一个”IRenderResource,所以,这个+16会被直接当做IRenderResource传入给ManagerResource。

但事实上,按照ManagerResource的实现,它所希望的并非+16的IRenderTexture所包含的那个IRenderResource,而是+8的IRenderResource本身:

MyResource* resource = static_cast<MyResource*>(InResource);

这句话所做的,是把InResource的指针地址-8,如果传入的是+8的IRenderResource,它正好索取到这个对象的起始位置,一切就都正常了。但是,我们传入的事实上却是+16,于是——

程序发生了未可预知的错误,请与提供者或者微软联系……


这个问题怎么解决呢?

虽然[Don Box]里没有讨论这个情况,但却讨论了一个跟这个相关的主题,最后有一个原则性的结论,请千万要记住:

接口不是C++指针!!

因此:IRenderTexture接口就是IRenderTexture接口,它不能被当做IRenderResource接口使用,它里面所包含的IRenderResource的部分,只是说明

“我Render Texture也具有这些部分的功能”。

但并不代表C++意义上的:“我Render Texture同时也是一个Render Resource”。

所以,如果遇到这种情况,应该这么做:

IRenderTexture* texture = XXXXSYstem()->CreateTexture();

...

IRenderResource* resource = (IRenderResource*)texture->QueryInterface(IID_IRenderResource);

if (resource){

XXXXSystem()->ManagerResource(resource);

resource->Release();

}

这样就完全没有问题了。


题外话:

用Direct3D,总得接触一些COM,当时初学的时候,啥都喜欢追根究底,还真搬弄着Don Box的《Com本质论》猛读了一阵,后来发现工作中根本没啥用途,Direct3D那能叫COM吗?只是一些连皮毛都不算的东西,每本书还都煞有介事地用这个概念来唬人。Direct3D那些所谓接口云云,跟其它C++API库没什么不同,QueryInterface您用么?不用吧。Marshal什么的您用么?也不用吧。什么“接口并非指针”的问题,咱们也不会关注吧?若非必要,dxguid.lib估计很多人都不会去装载。其实COM的概念比起Direct3D用的程度要复杂得多,要不微软也就不至于去推.NET了——COM写起来太累了啊!!!!!

一开始总觉得COM只是一个“更好地C++”,其实也提不上更好,因为很多C++好用的东西在COM中是无从体现的,而单纯以扩展性而言,比起具备强制二进制标准的纯C又好不了到哪去。不过后面慢慢习惯了COM那套概念以后,发现确实还是有好处的,不需要再回去写纯C,也不需要因此把很多本来很容易明白的概念封装成大量的函数和Handle,调用起来也很清晰,不会出现我把Texture Handle给扔到设置Vertex Buffer Object的地方。难了实现者,便宜了使用者(当然比起纯C++又不便宜,但是扩展性更好)。

分享到:
评论

相关推荐

    C++知识点,特别是重难点、易混淆知识点大全

    适用场景:适用于学习C++全过程,特别是考前只需看此资料即可无需再去看厚厚的书(本人考研时就是如此,这也是当时写此资料的一个初衷,虽然最后考研专业课改成数据结构--&gt;可参考本人另一个资源“数据结构重难点、...

    C语言高手总结的新手容易犯的错误

    字符常量是一个单个字符,括在单引号中,而字符串常量是一个字符序列,括在双引号中。例如,'a'是字符常量,而"a"是字符串常量。在编程中,需要正确地区分这两种常量,以避免错误。 2. 忽略了大小写字母的区别 ...

    新手编写高质量Python代码的38个小建议

    - 建立一个专门的`const.py`文件来存放所有常量,便于管理和导入,如`const.EXAMPLE1 = 1`。 6. **使用`assert`断言** - `assert`用于在测试阶段验证假设,如`assert condition, '信息'`。 - 断言会影响性能,不...

    C语言的基本知识(新手 问题)

    使用符号常量的好处在于一处修改,全局生效,提高了代码的可维护性。 数据类型是C语言的重要组成部分,它决定了数据如何存储和操作。C语言的数据类型主要包括: 1. 基本类型:如int(整型)、char(字符型)、float...

    阿里巴巴开发手册;开发规范;新手、老手程序员必备

    《阿里巴巴开发手册》是编程界的一部重要指南,尤其对于新手和经验丰富的程序员来说,它提供了全面而细致的开发规范,旨在提升代码质量和团队协作效率。手册覆盖了多个方面,包括但不限于常量定义、命名规范、注释...

    lucida sans typewriter

    总之,"Lucida Sans Typewriter"是一款为程序员量身打造的美观等宽字体,其独特的设计解决了易混淆字符的问题,提供了多样化的样式选择,并确保了多语言的兼容性。无论是新手还是资深开发者,都可以尝试使用这款字体...

    五笔拼音对照查询改进版

    软件能够提醒用户这些易混淆字的正确写法,降低错字率,增强汉字书写的规范性。 综上所述,《五笔拼音对照查询改进版》不仅是一个输入辅助工具,更是一个汉字学习和纠正错误的好帮手。无论你是五笔输入法的资深用户...

    c语言编码规范以及编程要求课件

    - 变量、函数、结构体等的命名应清晰、简洁,避免使用模糊不清或易引起混淆的名称。 - 命名应采用小写字母,多个单词组成时使用下划线分隔,如`my_variable_name`。 - 类型定义通常使用大写字母分隔,如`MY_...

    gb1.1 使用模板

    它可能指的是国家标准的第一个修订版本,或者是某一特定标准系列的第一部分。在中国,国家标准(GB)是指导各行各业技术活动的重要依据,其编号通常由GB+顺序号+修订号组成,如GB1.1可能是某一系列标准的第一版。 ...

    upath代码生成控件

    例如,创建一个新的文件路径,检查路径是否存在,或者找出目录中的所有匹配某个模式的文件。 5. **学习与使用** 学习upath通常涉及阅读官方文档,了解其提供的API,通过示例代码来熟悉每个函数的用法。实践是掌握...

    2019年软件测试工程师的个人总结汇报.doc

    互联网是一个充满宝藏的世界,各种开源代码、技术文档如同“武林秘籍”,诱惑着我去探索。然而,盲目收集并不等于掌握。在实际项目中,我曾过于依赖这些资源,导致解决问题的速度变慢,思路不清。项目经理的指导让我...

    并列关系的PowerPoint文本框素材下载.rar

    这种设计能够帮助观众清晰地理解各个部分之间的平行性,避免混淆,提高演示文稿的逻辑性和易读性。在这个“并列关系的PowerPoint文本框素材下载.rar”压缩包中,包含了一组专门设计用于展示并列关系的文本框模板,...

    网页小图标大全【已分类】

    这个资源包包含了上千个精心设计的图标,已经按照功能和用途进行了分类,对于网页美工来说,是一个非常实用的工具集合。 首先,我们要了解网页小图标的基本概念。图标是图形化设计的一种形式,通过简洁明了的图形来...

    反编译工具包集合.zip

    "反编译工具包集合.zip" 是一个包含三款针对Android APK文件的反编译工具的资源包,分别是jartool、dex2jar和gui。下面将详细介绍这三个工具及其在Android应用逆向工程中的作用。 1. **jartool**:这是一个用于处理...

    Java语言编码规范(Java Code Conventions).

    公共类总是文件中的第一个类,且每个Java源文件的结构通常包含开头注释、包声明、引入语句、以及类和接口声明。 类和接口的声明顺序有明确的规定,便于阅读和理解。类或接口的文档注释首当其冲,其次是声明本身。...

    如何编写批处理文件批处理文件批处理文件

    ”因为网上好像并没有一个比较完整的教材,所以抽一点时间写了这片《简明批处理教程》给新手朋友们.也献给所有为实现网络的自由与共享而努力的朋友们. 批处理文件是无格式的文本文件,它包含一条或多条命令。它的...

    245PPT素材

    在PPT设计中,素材的选择和使用至关重要,尤其对于新手来说,高质量的素材可以极大地提升PPT的整体视觉效果和表达力。"245PPT素材"这个压缩包提供了丰富的资源,旨在帮助用户优化年终总结报告,使得PPT更具吸引力。 ...

    jd-gui-windows-1.6.1.rar

    1. **直观的GUI**:用户友好的界面使得操作简单易行,无论是新手还是经验丰富的开发者都能快速上手。 2. **实时更新**:当你修改并重新加载.class文件时,显示的源代码会自动更新,反映了最新的反编译结果。 3. **...

    C程序设计(第三版). 很详尽

    此外,还涵盖了数组和指针,这是C语言中非常关键且易混淆的概念,作者通过实例解析了它们之间的关系和操作方式。 结构体和联合体是C语言中的复合数据类型,用于组织复杂的数据结构。书中详细介绍了如何定义和使用这...

    the element of programing style

    27. **持续调试**:发现一个bug后,不要停止,继续查找其他潜在的问题。 - 示例:使用静态分析工具和单元测试来检测和修复更多的错误。 28. **使用调试编译器**:利用调试编译器工具来帮助查找和修复错误。 - ...

Global site tag (gtag.js) - Google Analytics