一个全局对象管理类

一个全局对象管理类 
    作者:Panic 

    全局对象主要存在三个比较大的问题: 
一:全局对象的构造顺序是无法确定的,完全取决于编译器的实现。有些全局对象具有相互之间的依赖性,需要满足一定的构造或者析构顺序,这种不确定的构造顺序有可能会造成难以预料的错误。 
二:全局对象的构造/析构函数有可能会抛出异常,据我所知,主流C++编译器并不提供捕获全局对象构造/析构函数异常的机制。 
三:全局对象和函数内的静态对象,类的静态数据成员,他们之间的调用关系可能很复杂,对全局对象的直接引用会增加代码的耦合性,不利于代码维护。 
    现在就针对以上三个问题,提出对应的解决方案,虽然看起来很麻烦,不过还是有点用处的。 
    首先是构造顺序,解决构造顺序最简单的方法就是把所有全局对象都声明成指针,然后按照确定的顺序new和delete就搞定了。为了方便起见,构造一个global class用来管理这些全局对象的指针。声明如下(假设CA和CB是需要管理的全局对象):

class global_p 

public: 
//构造和析构函数: 
    global_p(); 
    ~global_p(); 
private: 
//类指针声明成私有成员。 
CA * m_pA; 
CB * m_pB; 
}

    这样,只要在构造函数里面new,在析构函数里面delete就可以了。构造和析构的顺序完全由你来决定。比如在对应的cpp文件里: 
global_p::global_p() 

    m_pA = new CA; 
    m_pB = new CB; 
}

global_p::~global_p() 

    delete pB; 
    delete pA; 
}

这样就很简单的实现了顺序构造,逆序析构。而与此同时,第二个问题也迎刃而解了,只要把new和delete的语句用try...catch包围起来,就能够捕获CA和CB构造/析构时抛出的异常。 
    这时候我们面临一个问题,就是现在仍然需要用global_p定义为一个全局对象,而且必须保证这个对象是唯一的,这很容易让人想起设计模式中的singleton,单件。C++实现这个非常简单,只要声明构造函数和析构函数为私有,然后添加一个static成员函数,返回一个自身的static实例就可以了。 
修改后的代码如下: 
//.h文件 
class global_p 

public: 
    static global_p & Instance(); //获取全局唯一的实例。 
    ~global_p();//析构函数公有 
private: 
    global_p();//构造函数私有

//类指针声明成私有成员。 
    CA * m_pA; 
    CB * m_pB; 
};

//.cpp文件 
global_p & global_p::Instance() 

    static global_p gp; 
    return gp; 

global_p::global_p() 

    try 
    { 
        m_pA  = new CA; 
        m_pB = new CB; 
    } 
    catch(...) 
    { //这里添加你的异常处理代码,当然也可以对每个new单独catch 
    } 
}

global_p::~global_p() 

    try 
    { 
        delete m_pB; 
        delete m_pA; 
    } 
    catch(...) 
    { //这里添加你的异常处理代码。 
    } 
}

    到现在为止,一个比较安全和易于控制的全局对象管理器就构造成功了,下面开始实现对其内部成员的访问控制。最简单的方法就是把成员变量转移到public域,但是这样有可能带来其他不好的后果。 
    在此,我打算用一种比较怪异的方式实现访问: 
    首先提一下对类成员的重载,这种重载包括了对类型转化的重载,也就是我想要使用的方法: 
    为类global_p添加如下公有成员方法: 
    operator CA & (); 
    operator CB & (); 
    实现: 
    global_p::operator CA & () 
    { 
        return *m_pA; 
    } 
    
    global_p::operator CB & () 
    { 
        return *m_pB; 
    } 
    
    于是所有的访问都变得直接了: 
    只要 ( (CA&)global_p.Instance()) 就得到了CA对象的全局唯一实例。但是这个形式看起来还是很麻烦,而且难以理解,为了让最终的调用看起来更顺眼一些,我们需要借助一下template的魔力。 
    template<class T> 
    T &g_() 
    { 
        return ((T&)global_p::Instance()); 
    } 
    
    好了,现在我们可以用 
    g_<CA>()这种很直观的形式来调用CA的全局唯一实例了,对于只需要有一个实例的全局对象来说,这个实例已经能够满足全部安全和有效的需求了。尽管代码看起来很繁琐,不过因为全局对象的数量一般而言都是有限的,并且在开发过程中修改的频率也比较低,所以还是可以忍受的。 
    
    以下是完整代码(包括测试代码): 
//.h文件 
#include <iostream> 
using namespace std; 
    
class CA 

public: 
    void Print() { cout << "CA " << endl; } 
};

class CB 

public: 
    void Print() { cout << "CB " << endl; } 
};

class global_p 

public: 
    static global_p & Instance(); //获取全局唯一的实例。 
    operator CA & (); 
    operator CB & ();

    //析构函数 
    ~global_p(); 
private: 
  
    //构造函数私有: 
    global_p();   

    //类指针声明成私有成员。 
    CA * m_pA; 
    CB * m_pB; 
};

//引用全局对象用的模板。 
template<class T> 
T &g_() 

    return ((T&)global_p::Instance()); 
}

//.cpp文件

global_p::global_p() 

    try 
    { 
        m_pA  = new CA; 
        m_pB = new CB; 
    } 
    catch(...) 
    { //这里添加你的异常处理代码,当然也可以对每个new单独catch。 
    } 
}

global_p::~global_p() 

    try 
    { 
        delete m_pB; 
        delete m_pA; 
    } 
    catch(...) 
    { //这里添加你的异常处理代码。 
    } 
}

global_p& global_p::Instance() 

    static global_p gp; 
    return gp; 
}

global_p::operator CA & () 

    return *m_pA; 
}

global_p::operator CB & () 

    return *m_pB; 
}

//测试代码 
void main() 

    g_<CA>().Print(); 
    g_<CB>().Print(); 

    
    这种实现方法仍然存在几个比较大的问题, 
    首先,某种类型的全局变量只能有一个, 
    其次,并不能保证这个实例的析构时间在其他静态对象之后, 
    第三,因为使用了模板,编辑和调试的难度增加了, 
    最后,如果代码中有对new,delete等操作符的重载,或者CA,CB拥有特殊构造/析构手法,代码的有效性就会大打折扣。 
    为了解决这几个问题,可以对T &g_()增加额外的模板参数,从而实现同一类型变量多个实例,第二个问题,可以参考《C++设计新思维》(候捷译)中关于singleton不同实现的内容部分解决global_p实例析构过早的问题。最后两个问题只能由编码者自己解决了:P

           -------by Panic,2005年1月11日晚19:49分于厦门。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值