COM编程(1)-- 为什么需要COM

25 篇文章 4 订阅
2 篇文章 0 订阅
本文探讨了C++动态链接库(DLL)的局限性,尤其是在类结构变动导致二进制不兼容的问题。通过实例展示了如何因类内部优化引发的重新编译问题。文章重点介绍了微软COM模型的引入,以提供跨编译器、二进制兼容的组件解决方案。
摘要由CSDN通过智能技术生成

Windows所支持的动态链接库(dll),对软件的开发和维护提供了极大的便利。dll把程序分成若干个模块,某个模块更新的时候,只需要更新对应的dll即可。编译器按照一定调用约定,调用dll中的函数,并返回值。dll的使用请参阅:DLL教程 - 如何编写动态链接库_Fisher-CSDN博客_dll教程

1、C++中dll的局限性

为了说明这个问题,请看下面的一个例程。使用C++开发了一个字符串处理的类,这个字符串类的功能十分强大,现在将这个类封装成了dll来向外发布。字符串处理类为FastString,其代码如下:

// FastString.h
class __declspec(dllexport) FastString
{
public:
	FastString(const char* ch);
	~FastString();
	int Length() const;
private:
	char* m_char;
};
// FastString.cpp
#include "FastString.h"
#include <cstring>
#include <new>

FastString::FastString(const char* ch)
	: m_char(new char[strlen(ch) + 1])
{
	strcpy(m_char, ch);
}

FastString::~FastString()
{
	delete[] m_char;
}

int FastString::Length() const
{
	return strlen(m_char);
}

 某个用户A使用了这个类,并编写的代码如下:

#include <iostream>
#include "FastString.h"

int main()
{
	FastString fs("Hello Word");
	std::cout << "Length:" << fs.Length() << "\n";
}

编译运行后,效果正确,运行如下:

一切皆大欢喜。

但是, FastString类的实现者发现,Length函数可以优化,其实在构造的时候,已经求过一次字符串长度,可以定义一个成员变量存储这个长度,于是,Length函数只需要直接返回这个成员变量即可。优化后的代码如下:

// FastString.h
class __declspec(dllexport) FastString
{
public:
	FastString(const char* ch);
	~FastString();
	int Length() const;
private:
	int m_len;
	char* m_char;
};

// FastString.cpp
#include "FastString.h"
#include <cstring>
#include <new>


FastString::FastString(const char* ch)
	: m_len(strlen(ch))
{
    m_char = new char[m_len + 1];
	strcpy(m_char, ch);
}

FastString::~FastString()
{
	delete[] m_char;
}

int FastString::Length() const
{
	return m_len;
}

 对于刚刚的程序A,必须重新编译,才能正确运行。这是因为,在程序A中,要构造一个FastString对象,编译程序A的编译器需要知道FastString类占用的字节数,才能正确构造对象。上面的例程中,因为FastString类新增了成员变量,于是占用的字节会增加,因此,使用了FastString这个字符串类的应用程序必须重新编译。

对于这种发布给其他用户使用的库,假如每一次升级,依赖它的其他应用都需要重新编译,这是不可能的、也是不能被接受了。

造成这种问题的原因是因为dll模块的FastString类,直接暴露给了应用程序,紧接着FastString类改变,造成了二进制层面的不兼容。为了解决这个问题,必须要想出一种方法,使得暴露给用户的代码,在二进制层面上不会再改变。

C语言之所以不会出现这样的问题,是因为它的模型简单得多——清晰的调用约定,清晰的函数名匹配方式。C++则会复杂很多,如构造函数、析构函数、虚基类、虚表,C++规范只在行为上进行了约束,并没有在实现上或二进制上进行约束。为了能跨越编译器起到一致的效果,我们必须要隔离编译器相关的实现部分,不得出现跨边界的编译器相关行为。

基于以上2个原因(当然还有更多原因),微软在1993年发布了COM模型,之后又发布了一系列支持的接口(OLE, ActiveX, ATL等)。通过COM模型,我们可以编写出可分发的、跨编译器的、二进制兼容的C++组件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值