1、方法一 将其构造函数声明为私有的

最直观的解决方法就是将其构造函数声明为私有的,这样就可以阻止子类构造对象了。但是这样的话,就无法构造本身的对象了,就无法利用了。
既然这样,我们又可以想定义一个静态方法来构造类和释放类。

#include<iostream>
using namespace std;
class A
{
    public:
       static A* Construct(int n)
       {
           A *pa = new A;
           pa->num = n;
           cout<<"num is:"<<pa->num<<endl;
           return pa;
       }
       static void Destruct(A * pIntance)
       {
           delete pIntance;
           pIntance = NULL;
       }
    
    private:
       A(){}
       ~A(){}

    public:
       int num;
};

int main()
{
    A *f = A::Construct(9);
    cout<<f->num<<endl;
    A::Destruct(f);
    return 0;
}

2、方法二 利用友元不能被继承的特性,可以实现这样的类。

设计一个模板辅助类 Base,将构造函数声明为私有的;再设计一个不能继承的类 FinalClass,将 FinalClass 作为 Base 的友元类。FinalClass 虚继承 Base。

#include <iostream>
using namespace std;

template <typename T>
class Base{
    friend T;
private:
    Base(){
        cout << "base" << endl;
    }
    ~Base(){}
};

class FinalClass : virtual public Base<FinalClass>{  
 //一定注意 必须是虚继承
public:
    FinalClass(){
        cout << "FinalClass()" << endl;
    }
};

class C : public FinalClass {
public:
    C(){}     //继承时报错,无法通过编译
};

int main(){
    FinalClass b;      //B类无法被继承
    //C c;
    return 0;
}

类 Base 的构造函数和析构函数因为是私有的,只有 Base 类的友元可以访问,FinalClass 类在继承时将模板的参数设置为了 FinalClass 类,所以构造 FinalClass 类对象时们可以直接访问父类(Base)的构造函数。

为什么必须是虚继承呢?

虚继承的功能是:当出现了菱形继承体系的时候,使用虚继承可以防止二义性,即子孙类不会继承多个原始祖先类。

那么虚继承如何解决这种二义性的呢?从具有虚基类的类继承的类在初始化时进行了特殊处理,在虚派生中,由最低层次的派生类的构造函数初始化虚基类。

结合上面的代码来解释:C 在调用构造函数时,不会先调用 FinalClass 的构造函数,而是直接调用 Base 的构造函数,C 不是 Base 的友元类,所以无法访问。这样的话 C 就不能继承 FinalClass。

注 C++11 的已经加入了 final 关键字,直接在类后面加上 final 关键字,就可以防止该类被继承。