在Interface中覆盖模板成员

时间:2014-03-15 10:56:00

标签: c++ templates

是否可以使用我可以在派生类中覆盖的模板方法声明某种类型的基类?以下示例:

#include <iostream>
#include <stdexcept>
#include <string>

class Base
{
public:
    template<typename T>
    std::string method() { return "Base"; }
};

class Derived : public Base
{
public:
    template<typename T>
    std::string method() override { return "Derived"; }
};

int main()
{
    Base *b = new Derived();
    std::cout << b->method<bool>() << std::endl;
    return 0;
}

我希望Derived作为输出,但它是Base。我假设有必要创建一个模板化的包装类,它接收实现类作为模板参数。但我想确定。

4 个答案:

答案 0 :(得分:7)

1)为了具有多态性,您的功能应标有虚拟

2)模板化的函数在POI处实例化,不能是虚拟的(签名是什么?你保留多少个vtable条目?)。 模板化函数是编译时机制,虚函数是运行时函数

一些可能的解决方案包括:

答案 1 :(得分:3)

模板方法不能是虚拟的。一种解决方案是使用静态多态来模拟&#34;模板虚拟&#34;方法:

#include <iostream>
#include <stdexcept>
#include <string>

template<typename D>
class Base
{
    template<typename T>
    std::string _method() { return "Base"; }
public:

    template<typename T>
    std::string method()
    {
       return static_cast<D&>(*this).template _method<T>();
    }
};

class Derived : public Base<Derived>
{
    friend class Base<Derived>;

    template<typename T>
    std::string _method() { return "Derived"; }
public:
    //...
};

int main()
{
    Base<Derived> *b = new Derived();
    std::cout << b->method<bool>() << std::endl;
    return 0;
}

其中method是接口,_method是实现。要模拟纯虚拟方法,_method将缺少Base

不幸的是,这种方式Base更改为Base<Derived>,因此您无法再例如Base*有一个const的容器。

另请注意,对于static_cast<D&>方法,static_cast<const D&>更改为&&。同样,对于rvalue-reference(static_cast<D&&>)方法,它会更改为{{1}}。

答案 2 :(得分:2)

使您的示例按预期工作的另一种可能方法是使用std::function

class Base {
  public:
    Base() {
      virtualFunction = [] () -> string { return {"Base"}; };
    }
    template <class T> string do_smth() { return virtualFunction(); }
    function<string()> virtualFunction;
};
class Derived : public Base {
  public:
    Derived() {
      virtualFunction = [] () -> string { return {"Derived"}; };
    }
};

int main() {
  auto ptr = unique_ptr<Base>(new Derived);
  cout << ptr->do_smth<bool>() << endl;
}

此输出&#34;派生&#34;。我不确定这是你真正想要的,但我希望它能帮到你..

答案 3 :(得分:0)

我遇到了同样的问题,但实际上我想出了一个可行的解决方案。显示解决方案的最佳方法是通过示例:

我们想要的东西(无效,因为您没有虚拟模板)

class Base
{
    template <class T>
    virtual T func(T a, T b) {};
}

class Derived
{
    template <class T>
    T func(T a, T b) { return a + b; };
}

int main()
{
    Base* obj = new Derived();
    std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
    return 0;
}

解决方案(打印3HelloWorld0.3):

class BaseType
{
public:
    virtual BaseType* add(BaseType* b) { return {}; };
};

template <class T>
class Type : public BaseType
{
public:
    Type(T t) : value(t) {};
    BaseType* add(BaseType* b)
    {
        Type<T>* a = new Type<T>(value + ((Type<T>*)b)->value);
        return a;
    };

    T getValue() { return value; };
private:
    T value;
};

class Base
{
public:
    virtual BaseType* function(BaseType* a, BaseType* b) { return {}; };
    template <class T>
    T func(T a, T b)
    {
        BaseType* argA = new Type<T>(a);
        BaseType* argB = new Type<T>(b);
        BaseType* value = this->function(argA, argB);
        T result = ((Type<T>*)value)->getValue();
        delete argA;
        delete argB;
        delete value;
        return result;
    };
};

class Derived : public Base
{
public:
    BaseType* function(BaseType* a, BaseType* b)
    {
        return a->add(b);
    };
};

int main()
{
    Base* obj = new Derived();
    std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
    return 0;
}

我们使用BaseType类表示您通常在模板中使用的任何数据类型或类。您将在模板中使用的成员(可能还有运算符)在此处带有虚拟标记。请注意,指针是使多态性发挥作用所必需的。

Type是扩展Derived的模板类。实际上,这代表一种特定的类型,例如Type<int>。此类非常重要,因为它使我们可以将任何类型转换为BaseType。我们在BaseType中描述的成员定义在此处实现。

function是我们要覆盖的功能。代替使用真实的模板,我们使用指向BaseType的指针来表示类型名。实际的模板函数在定义为Base的{​​{1}}类中。它基本上只是调用func并将function转换为T。如果现在从Type<T>扩展并覆盖Base,则将为派生类调用新的覆盖函数。

相关问题