我无法覆盖基类的方法,因为我的派生类是模板化的
Posted
技术标签:
【中文标题】我无法覆盖基类的方法,因为我的派生类是模板化的【英文标题】: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 <class T> std::vector<NumberType<T>> numbers;
来避免丢失类型信息。
我正在尝试抽象出不同的数据类型,这样我就可以拥有一个不同类型的容器,我认为他们称之为类型擦除?这是为了创建我自己的脚本,您可以在运行时动态创建自己的类,但看起来这是不可能的。
【参考方案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;
;
其中T
是Cov
的子类:这种关系意味着T&
是与Cov&
协变的返回类型,因此编译将成功。这样做还可以避免获取T
的值副本。您可能还会发现为各种 T
s 构建 conversion 运算符很方便,这些运算符最终会被构建为具有原始类型返回值。
您还可以引入const
引用返回类型以满足确切的要求。
【讨论】:
从答案中的示例代码来看,int
和 double
都不是 Cov
的子类。如果没有答案中未解释的额外机器,它将无法解决问题。
这非常非常有趣。协变,这是 Visual Studio 使用的词,表示它必须是协变的。这看起来很有趣,我去看看我能做什么。
@skypjack 是的,这是我想到的第一件事,然后我想我只是将原始数据类型包装在类中。哇,有无穷无尽的解决方案。好吧,这可能是个坏主意,但我仍然喜欢看到这有多疯狂。
如果您确实在类中包装了原始类型,那么您还可以在这些类中定义 conversion 运算符来生成原始类型!
@Zebrafish 好吧,如果您可以随意更改 everything 的定义,那么可以:有很多不同的解决方案。【参考方案2】:
BaseType
有一个对其所有后代都具有约束力的合同。它说getPropertyValue
返回double
。 NumberType
不能修改合同,它是一成不变的。
让我们假装合同不存在。
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
的可用接口,并在所有后代类中坚持下去。
【讨论】:
以上是关于我无法覆盖基类的方法,因为我的派生类是模板化的的主要内容,如果未能解决你的问题,请参考以下文章