基类在编译时派生的模板类的大小

时间:2019-01-05 11:28:50

标签: c++ templates polymorphism

我有一个使用多态容器来保存派生模板类实例的现有体系结构。现在,我需要在基类中重写一个运算符,并在编译时声明一个具有派生类大小的类型。
该体系结构如下图所示: enter image description here

我已经在基类头中尝试了模板类的前向声明,但没有成功。而且我还尝试从基类中制作一个模板以获取类类型,但这不适用于多态容器。

预先感谢

1 个答案:

答案 0 :(得分:2)

设计的问题在于,如果Model类不知道派生类的大小,则无法知道它的大小。 如您所正确说明的那样,将Model用作类模板本身将阻止您创建Models的动态容器。

要解决此问题,您可以添加一层静态多态性(也称为CRTP)以实现所需的功能。

这个想法是从模板化的基类Model派生ModelCRTPBase,然后将接口功能委托给实际的实现。

显然,不是Model类知道子级的大小,而是ModelCRTPBase。但是由于Model仅用作多态接口类,并且模型的所有常见功能都在ModelCRTPBase中(它知道编译时的大小),所以应该没有问题。

#include <iostream>
#include <vector>
#include <memory>


class Model {

public:
    virtual ~Model() {}
    virtual void print() = 0;
};

template<typename Derived>
class ModelCRTPBase : public Model {

    Derived& derived() {
        return static_cast<Derived&>(*this);
    }

public:

    static size_t  size() {
        return sizeof(Derived);
    }

    void print() override  {
        std::cout << "print Base, size = " << size() << '\n';
        derived().print_impl();
    }

};

template <typename T>
class ModelA : public ModelCRTPBase<ModelA<T>> {

public:

    void print_impl() {
        std::cout << "ModelA<" << typeid(T{}).name() << ">\n";
    }
};

template <typename T>
class ModelB : public ModelCRTPBase<ModelB<T>> {

    int payload;

public:

    void print_impl() {
        std::cout << "ModelB<" << typeid(T{}).name() << ">\n";
    }
};
int main() {

    std::vector<std::shared_ptr<Model>> vec;
    vec.push_back(std::make_shared<ModelA<int>>());
    vec.push_back(std::make_shared<ModelB<float>>());

    vec[0]->print();
    vec[1]->print();

}

输出:

print Base, size = 8
ModelA<i>
print Base, size = 16
ModelB<f>