我有一个使用多态容器来保存派生模板类实例的现有体系结构。现在,我需要在基类中重写一个运算符,并在编译时声明一个具有派生类大小的类型。
该体系结构如下图所示:
我已经在基类头中尝试了模板类的前向声明,但没有成功。而且我还尝试从基类中制作一个模板以获取类类型,但这不适用于多态容器。
预先感谢
答案 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>