ITK 中的智能指针与对象工厂演示-1

关于智能指针,一般有两种常用的策略,参考:智能指针;有一篇原创的智能指针写得不错:一个智能实现的改进

关于对象工厂,看到一篇写的不错的博文:泛化对象工厂简述

     在 ITK 中将智能指针与对象工厂结合。除少部分非常小的类之外,其它类都继承自 LightObject 或者 Object(其中,Object 也继承自 LightObject)。LightObjec 是 ITK 中最基层的轻量极类,它提供了增加/减少引用计数(Register()/UnRegister())以及打印对象信息(Print())的方法。ITK 中每个类都提供如下标准定义与函数:

typedef    classname    Self;                                  //表示自身

typedef    parentClass  Superclass;                       //表示父类;LightObject 是最顶基类,无此项

typedef     SmartPointer<classname>    Pointer;     //将该对象的指针包装成智能指针,供用户使用。

typedef    SmartPointer<const classname> ConstPointer;  //const SmartPointer

static  Pointer New();   //除了 LightObject 以外,其余类都是以宏定义 itkNewMacro(Self); 自动生成。

     ITK中,用户创建对象实例还是通过 new 操作符,而是以统一的格式:ClassName::Pointer   pclass = ClassName::New(); 即可得到指向该类实例对象的智能指针 pclass。其中,New() 通过使用对象工厂创建对象实例。因为智能指针的构造函数是 public 的,所以如上语句得到的智能指针是在“栈”上创建的,而其指向的对象实例则是在“堆”上创建的,所以当智能指针离开作用域时,就会自动析构。此时并不直接删除其所指向的对象,而是减少其引用计数,并且判断引用计数是否为 0,如果为 0 才删除。用户操作得到的智能指针,无论是进行拷贝、还是赋值都不会创建该对象的副本,而是增加该对象的引用计数,这样便实现了指针指向的对象的共享。

     对象工厂使得用户能够在运行时进行版本替换,程序中我们进行了演示。

     下面给出 ITK 中智能指针(SmartPointer)、以及对象工厂(ObjectFactory)的代码,这里的代码基本都是直接来自 ITK 源码,作了适当的裁减,里面做了比较详细的注释,其实现非常简洁漂亮,很值得借鉴。对象工厂部分比较麻烦,需要仔细研究。

 

1.几个宏,用于在类中生成统一的 New()、CreateAnother()、GetNameOfClass() 方法。

//MyMacro.h
#pragma once

//该宏会在类中生成两个用于创建对象的成员函数:
//1.static Pointer New(); 客户调用, 用于创建对象的接口, 使用对象工厂创建
//如果使用对象工厂创建失败, 则使用 new 操作符创建对象.
//New() 将一个原始指针赋值给 SmartPointer, 然后再调用原始指针的 UnRegister() 
//减少引用计数, 因为 MyObject 的构造函数会将引用计数初始化为 1.
//2.virtual MyObject::Pointer CreateAnother(void) const; 利用现有对象创建一个完全相同的对象
//这在需要向上类型转换时非常有用.
#define MyNewMacro(x) /
	static Pointer New(void)/
	{/
		Pointer smartPtr = MyObjectFactory<x>::Create(); /
		if(smartPtr.GetPointer() == NULL) /
		{ /
			smartPtr = new x; /
		} /
		smartPtr->UnRegister(); /
		return smartPtr; /
	} /
	virtual MyObject::Pointer CreateAnother(void) const /
	{ /
		MyObject::Pointer smartPtr; /
		smartPtr = x::New().GetPointer(); /
		return smartPtr; /
	}

//该宏会在类中生成两个用于创建对象的成员函数,但不使用对象工厂:
//1.static Pointer New(); 客户调用, 用于创建对象的接口, 注: 不使用对象工厂.
//New() 将一个原始指针赋值给 SmartPointer, 然后再调用原始指针的 UnRegister() 
//减少引用计数, 因为 MyObject 的构造函数会将引用计数初始化为 1.
//2.virtual MyObject::Pointer CreateAnother(void) const; 利用现有对象创建一个完全相同的对象
#define MyFactorylessNewMacro(x) /
	static Pointer New(void) /
{ /
	Pointer smartPtr; /
	x *rawPtr = new x; /
	smartPtr = rawPtr; /
	rawPtr->UnRegister(); /
	return smartPtr; /
} /
	virtual MyObject::Pointer CreateAnother(void) const /
{ /
	MyObject::Pointer smartPtr;         /
	smartPtr = x::New().GetPointer(); /
	return smartPtr; /
}

//运行时类型识别.
//virtual const char* GetNameOfClass() const;
#define MyTypeMacro(thisClass,superclass) /
	virtual const char *GetNameOfClass() const /
{/
	return #thisClass;/
}
 

 

2.临界区类,用于控制引用计数的增加与减少,保证其操作的原子性。

//MyFastMutexLock.h
#pragma once

//不同的平台需要定义不同的类型,这里只给出 windows32 例子
//不同平台在处理时有相应的优化策略, 以保证操作的原子性.
#if defined(_WIN32)
	#include "Windows.h"
	#include <winbase.h>
	typedef CRITICAL_SECTION FastMutexType;
#endif

//为了演示, 完全可以只使用 int 即可, 但无法提供真正的加锁功能
#ifndef _WIN32
	typedef int FastMutexType;	
#endif

//临界区锁类: 在修改临界值时, 对其加锁, 以保证修改的唯一原子性.
class MyFastMutexLock
{
public:
	typedef MyFastMutexLock   Self;

	//可以在栈上创建临界区对象, 所以将构造函数与析构函数设为 pubilc.
	MyFastMutexLock();
	~MyFastMutexLock();

	//Lock, 加锁, 使其它任何对象都不能修改被加锁的对象
	void Lock() const;

	//Unlock, 解锁
	void Unlock() const;

protected:
	mutable FastMutexType   m_FastMutexLock;
};
 

 

 

3.回调函数,与供对象工厂使用

//MyCreateObjectFunction.h
#pragma once
#include "MyObject.h"

//MyCreateObjectFunctionBase, 抽象基类.
//定义创建对象的回调函数(callback)
class MyCreateObjectFunctionBase: public MyObject
{
public:
	typedef MyCreateObjectFunctionBase		Self;
	typedef MyObject				Superclass;
	typedef MySmartPointer<Self>			Pointer;
	typedef MySmartPointer<const Self>		ConstPointer;

	//创建一个对象,并返回一个指向该对象的指针.
	virtual MySmartPointer<MyObject> CreateObject() = 0;

protected:
	MyCreateObjectFunctionBase() {	}
	~MyCreateObjectFunctionBase(){	}

private:
	MyCreateObjectFunctionBase(const Self&);
	void operator=(const Self&);  
};

//MyCreateObjectFunction: 
//具体的用于创建对象的回调函数, 与 "对象工厂" 一起使用.
template <class T>
class MyCreateObjectFunction : public MyCreateObjectFunctionBase
{
public:
	typedef MyCreateObjectFunction		Self;
	typedef MyCreateObjectFunctionBase  Superclass;
	typedef MySmartPointer<Self>		Pointer;
	typedef MySmartPointer<const Self>  ConstPointer;

	//用于创建 MyObject 对象的方法.
	MyFactorylessNewMacro(Self);
	MyObject::Pointer CreateObject() 
	{ 
		//std::cout << "MyCreateObjectFunction::CreateObject() ..." << std::endl;
		return T::New().GetPointer();
	}

protected:
	MyCreateObjectFunction() {	}
	~MyCreateObjectFunction() {	}
private:
	MyCreateObjectFunction(const Self&);
	void operator=(const Self&);
};
 

 

 

4.MySmartPointer:智能指针

//MySmartPointer.h
#pragma once
#include <iostream>

//
//在使用智能指针的类中,使用 typedef MySmartPointer<MyClass> Pointer; 将其包装成智能指针
//声明并定义方法静态方法New()它使用对象工厂创建对象实例(堆上),并返回一个指向该实例的智能指针.
//而且将该类的构造函数声明成保护类型,客户只能通过 New() 创建对象,且不需要手动释放。
//通过使用智能指针, 拷贝函数以及赋值操作符并不真正生成新的对象实例,从而实现指针指向对象的共享
//智能指针的构造函数是 public,所以能够在栈上分配,当离开作用域时智能指针会被自动删除.
//当该智能指针指向对象的引用计数减为 0 时, 才会真正删除其指向的对象.
//

//智能指针是模拟指针的行为,只要提供如下几个相应的实现即可:
//构造函数、析构函数、operator=、operator->、operator*
//智能指针自动调用对象的 Register()/UnRegister() 增加或减少引用计数
//关键的地方有几点:
//1.New() 通过对象工厂创建实例, 对象工厂的实现比较麻烦.
//2.Register()/UnRegister() 增加与减少引用计数, 它调用了被包装对象的同名函数. 
//  增加或减少引用计数需要考虑"临界值"的竞争问题, 不同平台有不同的实现.
//3.封装的指针应该隐式转换至原始的指针类型吗? 例如通常函数的参数接收的是原始
//  指针类型的参数. 应该允许这种隐式转换吗?因为隐式转换有潜在的危险(如被人不小心 
//	delete 等). 所以实现中使用一个函数来取得原始指针. 而不是用转换函数来隐式转换.
//4.拷贝构造函数: 增加右操作数的引用计数.
//5.赋值操作符(=): 增加右操作数的引用计数, 并减少左操作数的引用计数.

//-----------------------------------------------------------------------------------
//智能指针的关键技术在于: 构造栈上对象的生命期控制堆上构造的对象的生命期.
//因为在智能指针的内部,存储着堆对象的指针,而且在构析函数中调用delete行为
//即,智能指针在栈上构建, 而其存储的指针指向的对象则在堆上构建.
//-----------------------------------------------------------------------------------

//MySmartPointer 智能指针,通过重载 operator-> 、* 、= 实现智能指针.
//MySmartPointer 将某个"对象的指针"进行包装,使其成为一个智能指针
template <class TObjectType>
class MySmartPointer 
{
public:
	typedef TObjectType ObjectType;

	//默认构造函数, 将构造函数设为 public, 智能指针可能在栈上分配.
	//ITK 中大部分类的构造函数都为 protected, 所以不能在栈上创建对象
	//只能通过调用调用方法 New(), 而 New() 通过对象工厂创建对象
	//并返回一个智能指针控制其所指向对象的生存周期.
	MySmartPointer ()
	{
		//std::cout << "Smart  默认构造函数 /n";
		m_Pointer = 0; 
	}

	//有参构造函数, 增加其指向对象的引用计数, 共享指向的对象
	MySmartPointer (ObjectType *p): m_Pointer(p)
	{ 
		//std::cout << "Smart  有参构造函数: ";
		this->Register(); 
	}

	//拷贝构造函数, 增加引用计数. 
	MySmartPointer (const MySmartPointer<ObjectType> &p) : m_Pointer(p.m_Pointer)
	{ 
		//std::cout << "Smart  拷贝构造函数: ";
		this->Register();        //并不真正创建对象,只是增加引用计数.
	}

	//Destructor:
	//智能指针的关键技术:在于构造栈上对象的生命期控制堆上构造的对象的生命期.
	//因为在智能指针的内部,存储着堆对象的指针,而且在构析函数中调用delete行为
	//即,智能指针在栈上构建, 而其存储的指针指向的对象则在堆上构建.
	~MySmartPointer ()
	{
		//std::cout << "~Smart 析构函数:     /n";
		this->UnRegister(); 
		m_Pointer = 0;  
	}

	//重载操作符 operator -> 以及 *, 这两个操作符以及 = 是实现智能指针的关键.
	ObjectType *operator -> () const
	{ return m_Pointer; }

	//返回指向对象的指针
	operator ObjectType * () const		//注意其形式
	{ return m_Pointer; }

	//测试指针是否已经实例化
	bool IsNull() const{    return m_Pointer == 0; }

	//操作会重载,使用模板; 注意, 在模板类的内部再使用模板时,其名称应该不同
	template <typename TR>
	bool operator == ( TR r ) const
	{ 
		return (m_Pointer == static_cast<const ObjectType*>(r) );
	}
	template <typename TR>
	bool operator != ( TR r ) const
	{
		return (m_Pointer != static_cast<const ObjectType*>(r) );
	}
//*/

	//取得原始指针.
	ObjectType *GetPointer () const 
	{  return m_Pointer;  }

	//重载符值操作符 =, 参数为另一个智能指针.
	MySmartPointer &operator = (const MySmartPointer &r)
	{  
		return this->operator = (r.GetPointer()); //调用了下面的 = 重载形式
	} 
	
	//重载符值操作符, 参数为原始对象指针
	MySmartPointer &operator = (ObjectType *r)
	{
		//std::cout << "Smart 赋值 =, 左减, 右增 " << std::endl;
		if (m_Pointer != r)
		{
			//如下操作是在原始指针上
			ObjectType* tmp = m_Pointer;  //避免循环地解引用(UnRegister)
			m_Pointer = r;	
			this->Register();		 //1.增加右操作数的引用计数,因为 m_Pointer 指向了 r
			if ( tmp ) 
			{ 
				tmp->UnRegister();   //2.减少左操作数的引用计数
			}
		}
		return *this;
	}
private:
	//要进行包装的对象
	ObjectType*		m_Pointer;

	//Register() 增加引用计数; UnRegister() 减少引用计数.
	//引用计数在 ObjectType 中.
	void Register()
	{ 
		if(m_Pointer) { m_Pointer->Register(); }
	}
	void UnRegister()
	{
		if(m_Pointer) { m_Pointer->UnRegister(); }
	}
};  
 

 

5.MyObject 所有对象的基类,实现引用计数功能。

 //MyObject.h
#pragma once

#include "MyMacro.h"
#include "MyFastMutexLock.h"
#include "MySmartPointer.h"

#if defined(_WIN32)
  //To get LONG defined
  #include "Windows.h"
#endif

//MyObject 几乎是所有对象的基类, 实现引用计数功能, 
//代码基本来 ITK 中的 LightObject 类, LightObject 在 ITK 中是最顶层的类.
class MyObject
{
public:
	typedef MyObject					Self;
	typedef MySmartPointer<Self>        Pointer;		//包装为智能指针
	typedef MySmartPointer<const Self>  ConstPointer;

	//通过对象工厂创建对象的实例
	static Pointer New();

	//根据已存在的对象创建一新的对象实例,允许用户创建一个完全相同的对象
	//这在需要向上类型转换时非常有用***
	virtual Pointer CreateAnother() const;

	//使用 New() 的对象, 应该使用 Delete()
	//Delete() 会调用 UnRegister 减少引用计数
	//只有当该对象的引用计数减为 0 时才会真正删除对象
	virtual void Delete();

	//运行时类型识别, 返回某对象的具体类名.
	virtual const char *GetNameOfClass() const 
	{return "MyObject";}

	//Used to avoid dll boundary problems.
	void* operator new(size_t);
	void* operator new[](size_t);
	void operator delete(void*);
	void operator delete[](void*, size_t);

	//增加与减少引用计数
	virtual void Register() const;
	virtual void UnRegister() const;

	//返回该类对象实例的引用计数
	virtual int GetReferenceCount() const 
	{	return static_cast<int>(m_ReferenceCount);	}

	//设置该类对象的引用计数值.
	virtual void SetReferenceCount(int);

protected:
	MyObject() : m_ReferenceCount(1) {	}
	virtual ~MyObject(); 
		
	//不同的平台, 需要定义不同的类型, 这里只简单使用 int 型. 引用计数.
#if (defined(WIN32) || defined(_WIN32))
	typedef LONG InternalReferenceCountType;
#else
	typedef int InternalReferenceCountType;
#endif
	//引用计数
	mutable InternalReferenceCountType m_ReferenceCount;
	//mutable int	m_ReferenceCount;	

	//临界区锁, 用于对临界区变量加锁
	mutable MyFastMutexLock			m_ReferenceCountLock;
private:
	MyObject(const Self&);		         
	void operator=(const Self&); 
};
 
 
 

你可能感兴趣的:(ITK 中的智能指针与对象工厂演示-1)