面试题 48,不能被继承的类

C#的话,第一反应 sealed;Java的话第一反应 final;C++没这些关键字,毫无疑问,第一反应:把构造函数设为私有。当然,为了这个类本身依然能被实例化,我们需要提供另一个函数来构建实例。有点像单例模式,当然这里没有类是否已经存在的判断。

代码:

Class SealedClass{
public:
    static SealedClass* CreateInstance(){ return new SealedClass() };
private:
    SealedClass();
    ~SealedClass();
}

书上代码:

class SealedClass1
{
public:
    static SealedClass1* GetInstance() 
    {
        return new SealedClass1();
    }
 
    static void DeleteInstance( SealedClass1* pInstance)
    {
        delete pInstance;
    }
 
private:
    SealedClass1() {}
    ~SealedClass1() {}
};

 

当然这种解法的弊端显而易见:这个本身不能用new 来创建实例了。

书上提供了我没看懂的解法二。。。

template <typename T> class MakeSealed
{
    friend T;
 
private:
    MakeSealed() {}
    ~MakeSealed() {}
};
 
class SealedClass2 : virtual public MakeSealed<SealedClass2>
{
public:
    SealedClass2() {}
    ~SealedClass2() {}
};

// 如果试图从SealedClass1继承出新的类型,
// 将会导致编译错误。
/*
class Try2 : public SealedClass2
{
public:
    Try2() {}
    ~Try2() {}
};
*/

 

我们可以看到类SealdClass2继承自MakedSealed,而MakedSealed的构造函数竟然是私有的。解法二推翻了解法一的前提吗?

关键就在于“友元”,类SealdClass2是类MakedSealed的友元类型,从而依然可以调用MakedSealed的构造函数。

第二个关键:虚拟继承

因为类SealdClass2采用虚拟继承来继承自MakedSealed,那么对于SealdClass2的子类,他们的构造函数将不是调用其父类SealdClass2的构造函数,而是调用祖父类MakedSealed的构造函数,SealdClass2的子类不是MakedSealed的友元类型,所以会导致编译错误。

 

书上说这种解法在有的编译器上无法得到需要的结果。。。

 

posted on 2014-03-11 10:58  Felix Fang  阅读(204)  评论(0)    收藏  举报

导航