试题:实现一个不能被继承的类(上)

来源:互联网 发布:软件管理器 编辑:程序博客网 时间:2024/06/01 10:43

其实我们根本没法写出满足字面要求的代码, 其实我们要实现的是:写一个类, 使继承这个类的子类不能实例化对象(不论栈上还是堆上)

 

看了点书的人都会想到这个办法: 将自己的类的析构函数(或所有构造函数+拷贝构造函数)声明为private, 这样继承它的子类就不能实例化对象了

这个方法有一个缺点: 我们只能通过下面的方式创建对象了

1.在static成员函数(也可以是友元函数)中返回一个局部的static的类对象(每个函数返回的是同一个, 要多少个对象就得有多少个不同的函数)

2.定义一个类的static成员对象, 并声明为public的(要多少个都得在类的定义中写死)

3.动态地创建对象, 并通过在类中定义一个static成员函数(或友元函数)来动态销毁这些对象(也可以定义一个static成员函数(或友元函数)来动态创建对象)

总之, 用这种方法, 我们可以禁止派生类实例化对象, 但也使我们自己不能"正常的"实例化对象了

 

下面是网上流传的方法:

class A;class FinalMaker{private:    ~FinalMaker() { }    friend class A;};class A : virtual public FinalMaker{};class B : public A{public:    static void static_func() { }    static int value;};int B::value = 0;int main(){    A a;//  B b; // error    B::static_func();    B::value = 1;    return 0;}

原理自己体会去吧, 注意A必须用virtual继承才能达到目的, 现在A就是个让派生类不能实例化对象的类了, 无沦你是在栈上还是堆上都无法创建B的对象了

 

上面的代码没有任何问题, 功能也达到了, 但有一点小小的不足:

以后我们要定义C, D, E, F...类也有A这个功能怎么办? 给FinalMaker取名字是件麻烦的事, 可以想到的办法是:

1.协商名字, A的FinalMaker就叫AFinalMaker, F的FinalMaker就叫FFinalMaker

2.每加一个新的类就往FinalMaker的定义中加一个friend声明

当然我已经说了, 这是个小问题, 但作为程序员, 我们总是觉得不爽, 上面的方式都不够自由, 不过1的方法容易让我们想到模板, 没错, 我们可以把A, D, E, ...作为模板参数来做

 

下面网上流传的将FinalMaker实现成类模板的方式:

template <class T>class FinalMaker{private:    ~FinalMaker() { }    friend class T;};class A : virtual public FinalMaker<A>{};class B : public A{public:    static void static_func() { }    static int value;};int B::value = 0;int main(){    A a;//  B b; // error    B::static_func();    B::value = 1;    return 0;}

可惜这份代码在gcc上编译不过(听说vs2003可以), 错在这一句friend class T; 有人建议改成friend T; friend typename T; 这都是不对的, 其实, C++标准上也从来没说可以这么用