我的C++情结
经过近两个月的努力,我的第一个C++开源项目net_sf_interfacecpp的第一个版本0.1版终于问世了。
项目地址:
https://sourceforge.net/projects/interfacecpp/
源码下载地址
https://sourceforge.net/project/showfiles.php?group_id=211243
其中debug部分可以直接运行。
我接触C++已经有10年了。大学时代我在C,C++和VC++上耗费了无数的精力。可是直到毕业,一直都没能掌握C++。
毕业后,虽然曾经使用过很多种语言,但是对C++的不舍情结仍不时环绕着我。也许是“真正的程序员用C++”这句魔咒的作用吧!
每隔一两年,我都会重新捧起C++书籍研究。但每一次都是无功而返。
去年参加CSDN软件技术英雄会,有幸认识了两位C++的高手:阿蒙和许式伟。非常感谢他们告诉了我现在C++社区的最新技术进展和对我的忠告,真的是受益非浅。
C++对象生命周期管理
COM技术的缺点
我先是看了看COM技术。我觉得COM技术对于接口和实现的分离,很符合我最喜欢和擅长的Java的技术观点。
但后来我想了想,我觉得COM这种技术仍然有不少弱点。
1,太重量级化。COM技术的思想很简单,但是最后的野心非常大。需要太多我认为用不着的操作。如使用每一个COM对象,都需要询问它提供的接口。还需要使用注册表发布和寻找COM对象。太繁琐了!
2,COM的实现技术是基于C,而且是落伍的C的实现方法。它没有使用异常,而是使用一个32bit的指针/句柄作为返回值,来表示各种错误类型。这…实在太离谱了!C石器时代的产物!
3,COM技术实现了二进制兼容,也就是说多种语言都可以创建COM对象。C,C++,VB,Delphi等都可以创建COM对象,由此引入了不必要的复杂性。
而我,并不想使用除C++之外的其他编译型语言。
我计划使用四种语言:
C++写操作系统或硬件相关的程序,Java通过JNI调用C++程序,Java开发大部分程序,JRuby脚本进行快速开发。JavaScript开发Web脚本。
4,COM技术已经过时,被微软所抛弃!
由于COM技术固有的弱点,微软已经把工作重心转移到.NET平台上了。未来COM的生存环境将越来越少。
我不该花时间学习一门一只脚已经踩入坟墓的语言。
5,COM技术是微软私有技术,微软不重视的情况下,不会再有什么进步。
6,COM技术不能够跨平台。而我对于C++的期望是java的辅助。它需要能够运行在任何我的Java程序能够运行的地方!
所有这些原因,让我最终决定放弃COM。
对象生命周期管理技术的研究
但是COM技术的两项思想还是非常好的:
1,使用对象技术管理对象的生命周期。
2,面向接口编程。
C++的内存管理是C++最大的弱点,是我这么多年来一直不敢自称掌握C++的最大的拦路虎!对内存的自动管理机制,也是我对Java和.NET最欣赏的地方。
C++中的内存管理技术有3类:
1,基于构造和析构的智能指针管理。
2,基于对象引用技术的智能指针管理。
3,垃圾回收器。
基于构造和析构的智能指针管理
这种技术是为每一个C++类创建一个新的C++包装类。下面我用例子进行说明。假设,有一个名叫Object的C++类,我们想给它提供对象管理的功能。我们需要创建一个ObjectManage的包装类。
注:下面是伪代码,可能无法编译。
Class ObjectManage{
Private:
Object* pObject;
Public:
ObjectManage(void){
pObject=new Object();
};
Object* operator ->(){
Return pObject;
};
~ObjectManage(void){
Delete pObject;
};
}
我们在需要使用Object对象时,不使用Object类,而是使用包装器类ObjectManage。
{
ObjectManage objectManage;
objectManage->Obejct的方法();
}
退出作用域。objectManage对象就自动被删除,内部的Object对象也自动调用delete自动删除。
这样,我们就不需要为new和delete操心了,作用域会自动帮我们搞定。
基于对象引用技术的智能指针管理
还有一些是基于对象引用技术的智能指针。典型的代表是boost的share_ptr类。
它是一个模板,内部使用对象引用技术。可以让多个share_ptr对象管理和使用一个真正的对象。
垃圾回收器
C++中也有一些类似于Java的垃圾回收器库。我对此不是很熟悉。
有一些看法认为,垃圾回收器效率比智能指针低。
net_sf_interfacecpp采用的方案
我最后的结论是,应该使用基于对象引用的智能指针。但是,我不喜欢boost提供的那四个智能指针。它们让我很难直接使用被管理的对象。而且,用起来太复杂,限制太多。
我还是欣赏COM的对象引用计数的对象管理方案。
因此,我决定自己写一套开源的C++库,提供自己的C++对象生命周期管理方案。
这就是net_sf_interfacecpp项目诞生的一个起源。
C++的依赖注入容器
net_sf_interfacecpp项目创建想要解决的另一个问题,就是提供COM技术的第二个优点:面向接口编程。
Java的Spring容器是一个优秀的依赖注入容器。不仅可以促使你实现面向接口编程,而且能够自动装配对象,并且能够方便的替换对象!
我考察了一下C++社区的情况。找到了2个类似于Spring的开源的C++容器。
其中一个使用了源代码生成技术。每一次写完程序,都需要运行一个源代码生成器生成源代码,然后再编译。
这不方便且不说,而且我下载之后运行不了。可能是因为开发环境是Linux操作系统的。
另外一个使用了宏。
这两个依赖注入容器都不能令我满意。
因此,我想在net_sf_interfacecpp项目中提供一个C++的依赖注入容器,类似于Spring。
C++不同于Java和.NET,它没有反射,缺乏运行时动态创建对象的能力。但我们还是能够找到一种简单而有效的方法实现依赖注入容器,从而可以真正在C++中普及面向接口编程。
面向接口,才是面向对象编程的真意!
net_sf_interfacecpp项目中的依赖注入容器将在0.2版中实现。
net_sf_interfacecpp0.1版的东西
我认为面向对象语言最好是单根的,因此,我在net_sf_interfacecpp项目中提供了一个单根的类结构。所有类的基类是一个接口IObject。
namespace net_sf_interfacecpp_core_lang{
class NET_SF_INTERFACECPP_API IObject
{
private:
public:
IObject(void);
/**
公共方法
*/
virtual long getRef()=0;
//指向自己的引用增加
virtual long addRef()=0;
//指向自己的引用减少
virtual long release()=0;
//设置为永不删除
virtual void setSingleton()=0;
public:
virtual ~IObject(void);
};
}
这个接口定义了基于对象引用技术的方法。这就意味着,net_sf_interfacecpp项目中的所有类都在对象引用计数的管理下。
那么,net_sf_interfacecpp项目外部的C++类呢?怎么办?难道都需要重写,都需要实现IObject接口?
答案是:不必!
net_sf_interfacecpp项目中还提供了一个用于管理任何C++对象的生命周期的模板ObjectRefManage
template<typename T,int Policy=ObjectRefManageConstants::ItsObject,typename Function=Release<T,Policy>>
class ObjectRefManage:public IObject
关于模板技术,我要感谢C++社区的众位高手们。当时我想把模板放在dll内部发布,一直不成功。是C++社区的众位高手告诉我,模板只能够源代码发布。
下面是ObjectRefManage的源码:
//确保只被引入系统一次
#ifndef _net_sf_interfacecpp_core_lang_ObjectRefManage_h_
#pragma once
#include "..\net_sf_interfacecpp\IObject.h"
//下面是自定义的所有.cpp文件都需要引入的头文件
//#include "ConfigApp.h"
#include "..\net_sf_interfacecpp\Object.h"
#pragma comment(lib,"..\\debug\\net_sf_interfacecpp.lib")
/*
用于管理任意类的实例的生命周期,使之符合IObject接口
模板类必须定义在头文件中
NET_SF_INTERFACECPP_API
Function是一个函数对象,必须有以下方法:
void operator() (T* pT){
释放T对象的资源。
}
管理数组的例子
AClass* pAClass=new AClass[2]();
pAClass[0]=AClass();
pAClass[1]=AClass();
ObjectRefManage<AClass,ObjectRefManageConstants::ItsArray>* pObjectRefManage=new ObjectRefManage<AClass,ObjectRefManageConstants::ItsArray>(pAClass);
std::cout<<"引用技术:"<<pObjectRefManage->addRef()<<std::endl;
*/
namespace net_sf_interfacecpp_core_lang{
class ObjectRefManageConstants{
public:
static const int ItsObject=0;
static const int ItsArray=1;
virtual ~ObjectRefManageConstants(void);
};
//const int Constants::ItsObject=0;
//const int Constants::ItsArray=1;
template<typename T,int Policy>
class Release{
public:
virtual void operator() (T* pT){
//释放T对象的资源。
switch(Policy){
case ObjectRefManageConstants::ItsObject:
delete pT;
break;
case ObjectRefManageConstants::ItsArray:
delete[] pT;
break;
}
};
virtual ~Release(){};
};
template<typename T,int Policy=ObjectRefManageConstants::ItsObject,typename Function=Release<T,Policy>>
class ObjectRefManage:public IObject
{
private:
Function* function;
IObject* pIObject;
T* pT;
//copy构造函数
ObjectRefManage(const ObjectRefManage &that);
//重载等于操作符
ObjectRefManage& operator=(const ObjectRefManage &that);
//void operator delete(ObjectRefManage* thisPtr);
public:
virtual long getRef(){
return this->pIObject->getRef();
};
virtual T* getObjectPtrAndAddRef(){
this->addRef();
return this->pT;
};
virtual T* getObjectPtrNotAddRef(){
return this->pT;
};
/*
提供一个被管理的对象的指针,并且提供一个释放该对象的函数对象
*/
ObjectRefManage(T* pThat,Function function){
//第一次,执行后,创建对象,引用技术是。
this->pIObject=new Object();
this->pT=pThat;
this->function=&function;
};
/*
用于传递一个没有默认构造器的对象。
请不要在外部删除它,现在开始,它由ObjectRefManage管理
*/
ObjectRefManage(T* pThat){
//第一次,执行后,创建对象,引用技术是。
this->pIObject=new Object();
this->pT=pThat;
this->function=0;
};
//默认构造器
ObjectRefManage(void){
//第一次,执行后,创建对象,引用技术是。
this->pIObject=new Object();
this->pT=new T();
this->function=0;
};
virtual long addRef(){
return this->pIObject->addRef();
};
virtual long release(){
long result=this->pIObject->release();
if(result==0){
delete this;
return 0;
}
return result;
};
virtual void setSingleton(){
this->pIObject->setSingleton();
};
public:
virtual ~ObjectRefManage(void){
//delete this->pIObject;
if(this->function==0){
switch(Policy){
case ObjectRefManageConstants::ItsObject:
delete this->pT;
break;
case ObjectRefManageConstants::ItsArray:
delete[] this->pT;
break;
}
}else{
(*this->function)(pT);
}
};
};
}
//确保只被引入系统一次
#define _net_sf_interfacecpp_core_lang_ObjectRefManage_h_
#endif
编后语
虽然我接触C++的时间不算短了。但我不是一个C++程序员,没有写过C++商业程序。就是在写net_sf_interfacecpp项目时,也还有很多C++语法没搞懂,是边学习,边开发。再加上平时工作很忙,没多少时间花在开发上面,因此肯定有很多毛病,如果发现,请告诉我,谢谢!
另外,本项目使用了STL,Boost,log4cxx,Xerces-C++,CppUnit这些第三方库。
另外,我之前写过一个Java的开源项目 OXmlEd。
https://sourceforge.net/projects/oxmled/
我打算再开发一个C++版本的OXmlEd,其底层实现使用Xerces-C++。