private inheritance

利用private inheritance产生出的类型安全的堆栈出口:
   考虑到一个常规的Stack template,每具现(instantiate)一次,编译时就会产生一份代码。当Stack中放置的数据的类型一多,就会产生很多的重复代码,即使 在template functions本来是可共享的情况下,template机制也还是会顽固的为每一种类型产生一份代码。这便是所谓的“因template而导致的程序 代码膨胀现象”,显然,不是一件好事情。
    于是,对于某些种类的classes,我们可以想到用泛型指针老避免上述膨胀现象。此时,classes内部存放的不再是对象,而是void *指针。具体实现如下:
(1)产生单一class,存放void *,指向各个对象。
(2)产生一组额外的classes,其唯一的目的是用来实现强制类型检查。
代码如下:
class GenericStack
{
public:
    GenericStack();
    ~GenericStack();
    void push(void *object);
    void *pop();
    bool empty() const;
private:
    struct StackNode
    {
          void *data;
          StackNode * next;
          StackNode(void *newData, StackNode *nexNode)
             :data(newData),next(nextNode){}
    };
    StackNode *top;
//阻止copying和assignment
    GenericStack(const GenericStack& rhs); 
    GenericStack& operator=(const GenericStack& rhs);
};
    由于这个class储存的是指针而非对象,所以有可能一个对象同时被多个堆栈参考到(也就是有可能同时被push到多个堆栈中)。虽然原来预想的目的实现了,但是,这个GenericStack class本身没有什么利用价值── 它太容易被误用了。client很容易误将一个指向cat对象类型指针push到一个打算用来放置int指针的堆栈中,而编译器也欣然接受。毕竟对于void *参数来言,指针就是指针,没有任何区别。即使把GenericStack设计成抽象类,基类指针也还是具有多态性。
    于是为GenericStack产生一个interface classes(facade模式),采用layering方案将GenericStack对象放置在那个interface类中,并设为 private。虽然要比上面安全了好多,但还是不彻底,因为你无法保证client绕过这个interface直接调用GenericStack,没有 办法阻止它。
    绝望了吗?不,我们还有或许最后一个选择。那就是private inheritance,别忘了它的意义也是“根据某物实现(implemented-in-terms-of)”,它只继承实现部分,接口部分略去,所 以并不意味着一种“是一种“isa”“关系,也就是说通过pivate inhertance的derived class对象(指针)不能被转换成它的base class对象(指针)。实施方案如下:
template<class T>
class Stack:private GenericStack
{
public:
    void push(T* objectPtr){ GenericStack::push(objectPtr) ; }
    T* pop(){ return static_cast<T*>(GenericStack::pop() );}
    bool empty() const{ return GenericStack::empty(); }  
};

这 真是一段令人惊艳的代码--虽然你一时不能注意(确实,此刻看第二遍,“惊艳”一词候老先生用的真是好),由于这个template,编译器会自动产生你 所需的任意个数的interface classes。这些classes都是型别安全的,所以如果client打错字,会在编译时期被侦测出来, 由于GenericStack的member functions是proctected属性, 而interface classes以GenericStack作为private base class,所以client不再绕过interface classes径自行为(指直接调用GenericStack的member funtion,那样的话很容易造成指针操作类型不一致)。由于每一个interface class member function都被(隐式)声明为inline,所以使用这些type-safe classes不会增加执行时期的成本;产生出来的代码就像直接使用GenericStack的效果一样。由于GenericStack使用void *指针,你只需为这段代码付出“一份拷贝”的成本,即可用来处理堆栈──不论你需要多少不同型别的堆栈。简单的说,这个设计带给你的是最高的效率和最高的 型别安全性。很难做得更好了。
//以上代码和以下评论均出自《Effective C++》之明确应用private inheritance。部分文字是俺加上去的。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值