【问题标题】:I can't override Base class's method because my derived class is templatised我无法覆盖基类的方法,因为我的派生类是模板化的
【发布时间】:2017-08-25 11:57:42
【问题描述】:

我尝试重写基类函数,但是因为我已经模板化了它的子类/派生类/子类,所以我不能根据实例化模板的类型来重写该函数。

struct BaseType
{
    virtual double getPropertyValue() = 0; 
};

template <typename T>
struct NumberType : BaseType
{
    T propertyValue;
    T getPropertyValue() override { return propertyValue; }  // I would like this to return whatever T is.
};

int main()
{
    std::vector<BaseType*> vectr;
    NumberType<double> doubleType;  // This is fine, overrides the base function
    NumberType<int> intType;    // Has no overrider, won't compile
}

所以我想也许我也可以模板化基类,以便基类函数也返回 T。但如果我这样做,我将无法将它们保存在容器中或指向它们,因为它们都属于不同的 Base 类型。

我还考虑过模板化 Base 并让它从更高的父级(未模板化)继承,但我遇到了同样的问题。

有没有办法解决这个问题?

【问题讨论】:

  • "我不能重写基类的方法,因为我的派生类是模板化的" 这不是你不能重写的原因。
  • 对不起,我知道这听起来如何,你是对的。不仅仅是因为我已经将它模板化了,还因为我有依赖于模板参数的返回类型。
  • 为什么你需要重写一个纯虚函数?在我看来,您正在混合静态和动态多态性。
  • 为什么要将不同的类型放入同一个容器中?由于类型差异,您将无法正确使用它们。您实际上可以使用template &lt;class T&gt; std::vector&lt;NumberType&lt;T&gt;&gt; numbers; 来避免丢失类型信息。
  • 我正在尝试抽象出不同的数据类型,这样我就可以拥有一个不同类型的容器,我认为他们称之为类型擦除?这是为了创建我自己的脚本,您可以在运行时动态创建自己的类,但看起来这是不可能的。

标签: c++ class inheritance polymorphism overriding


【解决方案1】:

如果返回值T 与纯虚函数的返回值协变,您可以执行此操作。但遗憾的是,T 通常不会与 double 协变。

接受你正在混合静态和动态多态性技术,这可能是一个设计缺陷,你可以定义

struct Cov {};

struct BaseType
{
    virtual Cov& getPropertyValue() = 0; 
};

那么,

template <typename T>
struct NumberType : BaseType
{
    T propertyValue;
    T& getPropertyValue() override { return propertyValue; }
};

其中TCov 的子类:这种关系意味着T&amp; 是与Cov&amp; 协变的返回类型,因此编译将成功。这样做还可以避免获取T 的值副本。您可能还会发现为各种 Ts 构建 conversion 运算符很方便,这些运算符最终会被构建为具有原始类型返回值。

您还可以引入const 引用返回类型以满足确切的要求。

【讨论】:

  • 从答案中的示例代码来看,intdouble 都不是 Cov 的子类。如果没有答案中未解释的额外机器,它将无法解决问题。
  • 这非常非常有趣。协变,这是 Visual Studio 使用的词,表示它必须是协变的。这看起来很有趣,我去看看我能做什么。
  • @skypjack 是的,这是我想到的第一件事,然后我想我只是将原始数据类型包装在类中。哇,有无穷无尽的解决方案。好吧,这可能是个坏主意,但我仍然喜欢看到这有多疯狂。
  • 如果您确实在类中包装了原始类型,那么您还可以在这些类中定义 conversion 运算符来生成原始类型!
  • @Zebrafish 好吧,如果您可以随意更改 everything 的定义,那么可以:有很多不同的解决方案。
【解决方案2】:

BaseType 有一个对其所有后代都具有约束力的合同。它说getPropertyValue 返回doubleNumberType 不能修改合同,它是一成不变的。

让我们假装合同不存在。

BaseType& base = BaseContainer.getSome();

// base can be NumberType<complex> or 
// or NumberType<tensor<double,4,4,4>> or NumberType<padic<5>>
// or a type that is not even thought of yet 
// as of now.

 what = base.getPropertyValue(); // how should 'what' be declared?

如果我们不知道base.getPropertyValue() 的结果是什么,就无法使用它。

使返回类型协变并没有真正的帮助。它只是将问题从BaseType 转移到BaseType::getPropertyValue() 返回的任何基类。

你需要想出一个BaseType的可用接口,并在所有后代类中坚持下去。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-01
    • 2012-09-15
    • 1970-01-01
    • 2016-06-14
    • 2016-03-17
    • 2017-06-22
    • 2017-06-12
    • 1970-01-01
    相关资源
    最近更新 更多