给定一个抽象类AbstractParentPrinter(即具有纯虚函数):

class AbstractParentPrinter {
public:
  virtual void print() = 0;
};


AbstractPrinterAbstractParentPrinter的(抽象)子类:

template<typename T, typename = std::enable_if<std::is_base_of<AbstractPrinterStore, T>::value>>
class AbstractPrinter : public AbstractParentPrinter {
protected:
  T& getPrinterStore() {
        return printerStore;
    }
private:
  static T printerStore;
};
template<typename T>
T AbstractPrinter <T>::printerStore;


PrinterAAbstractPrinter<PrinterStoreA>的子类。 PrinterStoreAAbstractPrinterStore的子类(未显示)。

class PrinterA : public AbstractPrinter<PrinterStoreA> {
public:
  void print() {
   // Do something with PrinterStoreA and print
   // An AbstractPrinterStore here instead would be not sufficient
   std::cout << "Printer A has printed!" << std::endl;
  }
};


由于AbstractPrinter<T>(与AbstractParentPrinter合并)不能存储在std::vector中,因此我为此创建了一个父类非模板类AbstractPrinter。如何防止来自AbstractParentPrinter的派生(除了AbstractPrinter)?

最佳答案

您可以将最基本的类的构造函数设为私有,然后将要从中派生的类作为它的朋友。

class AbstractParentPrinter
{
    private: AbstractParentPrinter()
    {}

    template<typename t> friend class AbstractPrinter;
};


另一种方法是限制对类的任何使用(而不仅仅是继承),例如,使用匿名名称空间或使其成为嵌套类。

====问题的简单通用答案如标题在此处结束====

在您的情况下,可以考虑更改结构,以便使用非虚拟接口模式。您将创建一个可以保留在向量中的非模板类,该类将拥有一个指向模板版本之一的指针。这是对pImpl模式的使用。

class AbstractParentPrinter;

class Printer
{

    AbstractParentPrinter* pImpl;


    public:

    void print();

    //add some constructor code/declaration to initialise pImpl to the correct template

};


您可以将AbstractParentPrinter嵌套在Printer中,也可以如上所述进行声明。如果嵌套它,则可以使用std :: unique_ptr,否则将在打印机的析构函数中将其删除。

在一个cpp中

class AbstractParentPrinter
{
    public: virtual void print() = 0;
};

// insert the template definitions here if you like

void Printer::print()
{
    pImpl->print();
}


这些模板甚至可以放在相同的cpp中(是的,在cpp中的模板-通常必须将它们放在头文件中的全部目的是使它们可被其他代码访问,但是我假设您提出这个问题的动机是隐藏这些实施细节)

因此,您仍然拥有原始的基类和实现打印的模板,但是现在您有了一个额外的非抽象,非模板的Printer类,但是拥有该类还有其他好处。您使用的代码不需要了解抽象类和模板-它可以只有一个Printers向量,不需要处理指向Printer的指针,因此可以简化打印机对象的生命周期管理。
Printer类创建的额外层还可以将调用代码与各种打印类的实现更改隔离起来。

08-05 22:01