活动介绍

实现编译器和供应商无关的接口设计与组件选择

立即解锁
发布时间: 2025-08-20 01:59:29 阅读量: 1 订阅数: 3
PDF

COM+编程实战:使用Visual C++和ATL构建企业级应用

### 实现编译器和供应商无关的接口设计与组件选择 #### 1. 接口作为抽象基类 在实现编译器独立性时,一个主要问题是不同编译器使用的非标准名称修饰方案。不过,如果客户端调用类的虚方法,客户端生成的机器语言代码不会通过符号名称引用该方法,而是使用虚表(vtbl)机制来调用方法。所以,若客户端仅调用虚方法,名称修饰就不再是问题。 但采用虚方法机制会带来三个新问题: - **数据成员问题**:若接口类包含数据成员,虚指针(vptr)在内存布局中的位置由供应商决定,可能导致不同供应商的实现不同。解决办法是在接口定义中不声明任何数据成员,这也符合向客户端隐藏实现细节的理念。 - **多重继承问题**:接口类的多重继承会使类的内存布局包含多个vptr,且vptr的顺序没有统一标准。可通过将派生限制为仅一个基类来解决。 - **虚表条目顺序问题**:客户端编译器假设虚表中的第一个条目是接口类中声明的第一个虚函数的地址,第二个条目是第二个虚函数的地址,以此类推。但对于重载的虚函数,这种假设在所有编译器中并不都成立。因此,接口类中不应允许重载函数声明。 为确保所有编译器为接口的客户端方法调用生成等效的机器语言代码,接口类定义应满足以下条件: - 仅包含纯虚方法 - 不包含任何重载的虚方法 - 不包含任何成员变量 - 最多从一个基类派生,且基类也需遵守相同的限制 按照这些规则定义接口类,就能实现接口类定义的编译器独立性。 这种定义的接口类称为抽象基类,对应的C++实现类必须从接口类派生,并使用有意义的实现覆盖每个纯虚方法。以下是将`IVideo`类重新定义为抽象基类以及`CVcr`类的对应实现代码: ```cpp // Video.h - Definition of interface IVideo class IVideo { public: virtual long _stdcall GetSignalValue() = 0; }; // File vcr.h #include "Video.h" class CVcr : public IVideo { public: CVcr(void); long _stdcall GetSignalValue(); private: long m_lCurValue; int m_nCurCount; }; ``` 这种机制不仅解决了编译器依赖问题,还解决了旧的不透明指针技术的一些弱点: - **性能损失**:旧技术每次方法调用会产生两次函数调用的成本,一次调用接口,一次嵌套调用实现。 - **易出错**:对于包含数百个方法的大型类库,编写前向调用不仅繁琐,还容易出现人为错误。 从抽象基类派生实现类可以解决这两个弱点。但新问题是,C++编译器不允许实例化抽象基类,只能实例化具体类(如实现类)。若向客户端透露实现类定义,会绕过接口类的二进制封装。 客户端实例化基类对象的合理方法是从DLL导出一个全局函数,该函数返回基类的新实例。只要该函数声明为`extern "C"`,客户端代码就不会遇到名称修饰问题。 ```cpp // Video.h extern "C" IVideo* _stdcall CreateVcr(); // Vcr.cpp (implementation) IVideo* _stdcall CreateVcr(void) { return new CVcr; } ``` 以下是使用该“工厂”机制的TV客户端代码: ```cpp #include "Video.h" #include <iostream.h> int main(int argc, char* argv[]) { int i; IVideo* pVideo = CreateVcr(); for(i=0; i<10; i++) { long val = pVideo->GetSignalValue(); cout << "Round: " << i << " - Value: " << val << endl; } delete pVideo; // we are done with it return 0; } ``` 不过,这段代码存在一个细微的缺陷:`pVideo`的`new`操作在VCR可执行文件中进行,而`delete`操作在TV可执行文件中进行。结果是`CVcr`类的析构函数永远不会被调用,若客户端和服务器使用不同的C++编译器,客户端的内存释放结果将不可预测。 一个可行的解决方案是在接口类中添加一个显式的`Delete`方法作为另一个纯虚函数,并让派生类在该方法的实现中删除自身。以下是修订后的`IVideo`接口类和`CVcr`实现类的定义: ```cpp // Video.h - Definition of interface IVideo class IVideo { public: virtual long _stdcall GetSignalValue() = 0; virtual void _stdcall Delete() = 0; }; // File vcr.h #include "Video.h" class CVcr : public IVideo { public: CVcr(void); long _stdcall GetSignalValue(); void _stdcall Delete(); private: long m_lCurValue; int m_nCurCount; }; // File vcr.cpp void CVcr::Delete() { delete this; } ``` 修订后的客户端代码如下: ```cpp int main(int argc, char* argv[]) { int i; IVideo* pVideo = CreateVcr(); for(i=0; i<10; i++) { long val = pVideo->GetSignalValue(); cout << "Round: " << i << " - Value: " << val << endl; } pVideo->Delete(); return 0; } ``` 综上所述,通过使用抽象基类定义接口、将`Delete`功能作为接口规范的一部分以及使用“工厂”方法获取接口,最终实现了编译器独立性。 #### 2. 组件的动态选择 回顾硬件电视和VCR的连接,只要VCR有符合预定义“视频”规格的视频输出插孔,任何品牌的VCR都能与电视配合使用。这是因为电视关注的是“视频”规格,而非VCR本身。实际上,也可以使用DVD播放器,只要其视频输出插孔能输出符合相同规格的视频信号,电视就能显示输出。 但现有的TV代码总是与特定供应商提供的VCR.dll链接,即使声称支持动态链接。为何不扩展模型以使用其他供应商提供的DLL呢?毕竟已经将接口与实现分离,如果另一个供应商为相同接口提供了更好的实现,理应能够使用新的实现。 然而,操作系统加载器会在执行时自动加载DLL,我们没有机会选择想要使用的DLL,这是因为客户端程序与导入库链接,该导入库包含指示操作系统加载器加载特定DLL的指令。 若要在运行时选择特定供应商的DLL,显然不能使用导入库机制。回顾使用导入库的原因是为了解决客户端程序外部的符号。在最新的接口定义中,程序外部的唯一符号是工厂方法`CreateVcr`。所以,若在客户端代码中自己加载DLL并解析该符号,就无需将程序与导入库链接。 微软提供了两个Win32 API来解决这个问题:`LoadLibrary`可用于动态加载DLL,`GetProcAddress`可用于解析过程入口点。可以编写一个客户端函数`CreateInstance`来实现以下功能: - 加载指定的DLL - 解析外部符号`CreateVcr` - 调用`CreateVcr`方法并返回接口指针 客户端代码如下: ```cpp IVideo* CreateInstance(char* pszDll) { // Define a pointer to the prototype of CreateVcr function typedef IVideo* (_stdcall *CREATEVCRPROC)(void); // Load the specified library HINSTANCE h = LoadLibrary(pszDll); // Obtain the procedure entry point for CreateVcr CREATEVCRPROC proc = reinterpret_cast<CREATEVCRPROC> (GetProcAddress(h, "CreateVcr")); // Execute "CreateVcr" indirectly return (*proc)(); } int main(int argc, char* argv[]) { int i; IVideo* pVideo = CreateInstance("vcr.dll"); for(i=0; i<10; i++) { long val = pVideo->GetSignalValue(); cou ```
corwn 最低0.47元/天 解锁专栏
赠100次下载
继续阅读 点击查看下一篇
profit 400次 会员资源下载次数
profit 300万+ 优质博客文章
profit 1000万+ 优质下载资源
profit 1000万+ 优质文库回答
复制全文

相关推荐

李_涛

知名公司架构师
拥有多年在大型科技公司的工作经验,曾在多个大厂担任技术主管和架构师一职。擅长设计和开发高效稳定的后端系统,熟练掌握多种后端开发语言和框架,包括Java、Python、Spring、Django等。精通关系型数据库和NoSQL数据库的设计和优化,能够有效地处理海量数据和复杂查询。
最低0.47元/天 解锁专栏
赠100次下载
百万级 高质量VIP文章无限畅学
千万级 优质资源任意下载
千万级 优质文库回答免费看

最新推荐

【评估情感分析模型】:准确解读准确率、召回率与F1分数

![Python实现新闻文本类情感分析(采用TF-IDF,余弦距离,情感依存等算法)](https://img-blog.csdnimg.cn/20210316153907487.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbGRu,size_16,color_FFFFFF,t_70) # 摘要 情感分析是自然语言处理领域的重要研究方向,它涉及从文本数据中识别和分类用户情感。本文首先介绍了情感分析模型的基本概念和评估指标,然后

【游戏物理引擎基础】:迷宫游戏中的物理效果实现

![基于C++-EasyX编写的益智迷宫小游戏项目源码.zip](https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/7eae7ef4-7fbf-4de2-b153-48a18c117e42/d9ytliu-34edfe51-a0eb-4516-a9d0-020c77a80aff.png/v1/fill/w_1024,h_547,q_80,strp/snap_2016_04_13_at_08_40_10_by_draconianrain_d9ytliu-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJh

MATLAB程序设计模式优化:提升pv_matlab项目可维护性的最佳实践

![MATLAB程序设计模式优化:提升pv_matlab项目可维护性的最佳实践](https://pgaleone.eu/images/unreal-coverage/cov-long.png) # 摘要 本文全面探讨了MATLAB程序设计模式的基础知识和最佳实践,包括代码的组织结构、面向对象编程、设计模式应用、性能优化、版本控制与协作以及测试与质量保证。通过对MATLAB代码结构化的深入分析,介绍了函数与脚本的差异和代码模块化的重要性。接着,本文详细讲解了面向对象编程中的类定义、继承、封装以及代码重用策略。在设计模式部分,本文探讨了创建型、结构型和行为型模式在MATLAB编程中的实现与应用

【BT-audio音频抓取工具比较】:主流工具功能对比与选择指南

# 摘要 本文旨在全面介绍BT-audio音频抓取工具,从理论基础、功能对比、实践应用到安全性与隐私保护等多个维度进行了深入探讨。通过分析音频信号的原理与格式、抓取工具的工作机制以及相关法律和伦理问题,本文详细阐述了不同音频抓取工具的技术特点和抓取效率。实践应用章节进一步讲解了音频抓取在不同场景中的应用方法和技巧,并提供了故障排除的指导。在讨论工具安全性与隐私保护时,强调了用户数据安全的重要性和提高工具安全性的策略。最后,本文对音频抓取工具的未来发展和市场需求进行了展望,并提出了选择合适工具的建议。整体而言,本文为音频抓取工具的用户提供了一个全面的参考资料和指导手册。 # 关键字 音频抓取;

【wxWidgets国际化与本地化】:构建全球友好的应用之道

![【wxWidgets国际化与本地化】:构建全球友好的应用之道](https://img-blog.csdnimg.cn/img_convert/2dcdeb71328106a2e1b793e7064e4b87.png) # 摘要 本文系统地探讨了wxWidgets框架下的国际化与本地化实践,阐述了国际化和本地化的基础理论、技术实现以及具体实施步骤。文章首先解释了国际化的重要性和基本概念,并深入探讨了字符编码和资源管理在wxWidgets中的处理方式。随后,文章提供了本地化实践中的详细步骤,包括处理文化差异和确保本地化质量的策略。此外,本文还通过构建国际化的应用实例,分享了界面设计、测试和

【从零开始的LMS算法仿真与验证】:Verilog新手必备教程

![【从零开始的LMS算法仿真与验证】:Verilog新手必备教程](https://www.edaboard.com/attachments/1673020046198-png.180600/) # 摘要 本文全面介绍最小均方(LMS)算法的理论基础、实现技术及其在实际系统中的应用。首先概述了LMS算法的基本原理和应用范围,随后深入探讨其工作机理,包括自适应滤波器的概念和数学模型。文中还详细分析了LMS算法的关键参数,如步长因子、权重更新和误差计算,以及性能评估,包括收敛速度、稳定性和误码率。第三章则专注于LMS算法的Verilog硬件实现,从基础知识到编码实践,再到仿真测试,提供了一个完

冷却系统设计的未来趋势:方波送风技术与数据中心效率

![fangbosongfeng1_风速udf_udf风_方波送风_](https://www.javelin-tech.com/3d/wp-content/uploads/hvac-tracer-study.jpg) # 摘要 本文综合探讨了冷却系统设计的基本原理及其在数据中心应用中的重要性,并深入分析了方波送风技术的理论基础、应用实践及优势。通过对比传统冷却技术,本文阐释了方波送风技术在提高能效比和增强系统稳定性方面的显著优势,并详细介绍了该技术在设计、部署、监测、维护及性能评估中的具体应用。进一步地,文章讨论了方波送风技术对数据中心冷却效率、运维成本以及可持续发展的影响,提出了优化方案

声纹识别故障诊断手册:IDMT-ISA-ELECTRIC-ENGINE数据集的问题分析与解决

![声纹识别故障诊断手册:IDMT-ISA-ELECTRIC-ENGINE数据集的问题分析与解决](https://i0.wp.com/syncedreview.com/wp-content/uploads/2020/07/20200713-01al_tcm100-5101770.jpg?fit=971%2C338&ssl=1) # 摘要 声纹识别技术在信息安全和身份验证领域中扮演着越来越重要的角色。本文首先对声纹识别技术进行了概述,然后详细介绍了IDMT-ISA-ELECTRIC-ENGINE数据集的基础信息,包括其构成特点、获取和预处理方法,以及如何验证和评估数据集质量。接着,文章深入探

CListCtrl字体与颜色搭配优化:打造视觉舒适界面技巧

![CListCtrl字体与颜色搭配优化:打造视觉舒适界面技巧](https://anchorpointegraphics.com/wp-content/uploads/2019/02/ColorContrastExamples-02.png) # 摘要 本文深入探讨了CListCtrl控件在Windows应用程序开发中的应用,涵盖了基础使用、字体优化、颜色搭配、视觉舒适性提升以及高级定制与扩展。通过详细分析CListCtrl的字体选择、渲染技术和颜色搭配原则,本文提出了提高用户体验和界面可读性的实践方法。同时,探讨了视觉效果的高级应用,性能优化策略,以及如何通过定制化和第三方库扩展List

【企业级应用高性能选择】:View堆栈效果库的挑选与应用

![View堆栈效果库](https://cdn.educba.com/academy/wp-content/uploads/2020/01/jQuery-fadeOut-1.jpg) # 摘要 堆栈效果库在企业级应用中扮演着至关重要的角色,它不仅影响着应用的性能和功能,还关系到企业业务的扩展和竞争力。本文首先从理论框架入手,系统介绍了堆栈效果库的分类和原理,以及企业在选择和应用堆栈效果库时应该考虑的标准。随后通过实践案例,深入探讨了在不同业务场景中挑选和集成堆栈效果库的策略,以及在应用过程中遇到的挑战和解决方案。文章最后展望了堆栈效果库的未来发展趋势,包括在前沿技术中的应用和创新,以及企业