我如何避免不允许使用模板虚拟功能

时间:2019-01-04 02:48:52

标签: c++ c++11

如何解决不支持模板化虚拟功能的问题?

我需要创建一个Builder / Command类,该类可以存储模板化的参数,该参数稍后可用于调用方法进行一些处理。

基本上,构建器应该能够存储模板化的值,也许有另一种(更正确的)方式来实现它。

设置所有值后,稍后我想调用一个execute方法,该方法将使用模板化的值来调用内部方法。

class BuilderImpl {
public:
    virtual void execute() = 0;
    virtual int type() = 0;
private:
    // common properties here
};

template <typename T1, typename T2>
class BuilderImpl2: public BuilderImpl {
public:
    BuilderImpl2(const T1 &v1, const T2 &v2) : mVar1{v1}, mVar2{v2} {
    }

    virtual void execute() override {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    virtual int type() override {
        return 2;
    }


    T1 mVar1;
    T2 mVar2;
};


template <typename T>
class BuilderImpl1: public BuilderImpl {
public:
    typedef BuilderImpl1<T> CLAZZ;

    BuilderImpl1(const T &v) : mVar1{v} {
    }

    virtual void execute() override {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    virtual int type() override {
        return 1;
    }

    template <typename T2>
    std::shared_ptr<BuilderImpl> add(const T2 &v2) {
        return std::make_shared<BuilderImpl2<T, T2>>(mVar1, v2);
    }

    T mVar1;
};

class Builder {
public:
    void execute() {
        std::cout << __FUNCTION__ << std::endl;

        if (mImpl) {
            mImpl->execute();
        }
    }

    template <typename T>
    void add(const T &v) {
        if (!mImpl) {
            mImpl = std::make_shared<BuilderImpl1<T>>(v);
        } else if (mImpl->type() == 1) {
            // How do I update my implementation mImpl to point with an instance of BuilderImpl2, any trick?
            //mImpl = std::static_pointer_cast<BuilderImpl1<???>>(mImpl)->add(v);
        }
    }

protected:
    std::shared_ptr<BuilderImpl> mImpl{ nullptr };
};

void templatebuilder() {
    Builder builder;
    builder.add(10);
    builder.add(0.0);
    builder.execute();
}

2 个答案:

答案 0 :(得分:2)

以自动,可扩展的方式执行此操作不可能:两个翻译单元可以定义类型AB,因此必须构造不可能的类型{{1 }}。 (这与以下事实有关:对于 n 输入类型,您需要 O(n ^ 2)实现。)

因此,您必须明确列出支持至少一侧的类型。最直接的方法是使用BuilderImpl2<A,B> s的阶梯:

dynamic_cast

(您可以添加一种方便的方法来编写if(const auto p=dynamic_cast<BuilderImpl1<A>>(mImpl.get())) mImpl=p->add(v); else if(const auto p=…) mImpl=p->add(v); // … else die_horribly(); 。)使用const auto p=mImpl->cast<A>()的动态类型进行索引可能有更好的方法,但这是一个单独的问题。

答案 1 :(得分:1)

这是对戴维斯答案的补充。

typedef BuilderImpl1<T> CLAZZ;行让您认为您已经习惯Java。 Java和C ++在这里有很大的区别:

  • Java使用类型擦除的泛型。任何专业化只有一类,并且在编译时仅应用控件
  • C ++使用模板。每个专业化都有一个不同的类,并且必须在编译时定义该类。这就是为什么必须在包含文件中包含模板化类的实现的原因,除非您知道将要使用的所有实现并在编译时声明它们。