【问题标题】:Polymorphism Fail多态性失败
【发布时间】:2014-06-07 05:29:44
【问题描述】:

我有一个非常简单的多态设置:带有虚方法的基类,重载方法的派生类。稍有不同的是,它们是模板类,而基类的方法会导致派生类的编译失败。由于基类的方法被重载,我认为这不会是一个问题,但显然这是一个问题。

为了说明问题,我已尽可能地精简代码。在这里。

DspBuffer.h

#include <vector>
#include <algorithm>
#include <cassert>

template <class T>
class DspBuffer {
 public:
    std::vector<T> buf;

    DspBuffer<T>(unsigned size) {buf = std::vector<T>(size);}
    virtual void sort() {std::sort(buf.begin(), buf.end());}
};

ComplexDspBuffer.h

#include <complex>
#include "DspBuffer.h"

template <class T>
class ComplexDspBuffer : public DspBuffer<T> {
 public:
    ComplexDspBuffer<T>(unsigned size) : DspBuffer<T>(size) {}
    void sort() {assert(false);}
};

main.cpp

#include "ComplexDspBuffer.h"

int main(int argc, char **argv) {
    ComplexDspBuffer< std::complex<double> > buf(1);
    return 0;
}

在我看来,这不应该是构建的问题,但编译器(Xcode 5.0.2)会产生如下错误 - “/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain /usr/lib/c++/v1/algorithm:644:97:二进制表达式的操作数无效('const std::__1::complex' 和 'const std::__1::complex')”。

它指的是 std::sort 使用的模板化 __less 函数。换句话说,就是构建 DspBuffer.sort() 方法,即使它不能被调用,或者至少不能被调用。我做错了什么,还是有一个不能与派生类的数据类型一起使用的基类方法?

【问题讨论】:

  • #include &lt;algorithm&gt;在哪里?
  • @PaulMcKenzie 很好。我编辑了我的代码和问题,但错误是一样的。
  • 将 void sort() = delete;是更好的继承选择?我现在明白基类被称为。嗯..
  • 实例化基类时可能需要 std::conditional 吗?

标签: c++ xcode templates polymorphism


【解决方案1】:

首先,您应该正确使用术语:重载(意味着使用一个函数名与不同的参数一起使用)和 覆盖(意味着替换)之间存在差异派生类中具有更专业版本的虚函数。据我所知,在所有使用重载的情况下,实际上意味着覆盖。

任何具体的虚函数总是可以被调用,即使它被覆盖:你可以用相应的基类的名字来限定函数调用,例如:

buf.DspBuffer<std::complex<double>>::sort();

将调用基类版本。此外,在对象的生命周期中,它实际上改变了它的类型:在类的构造函数和析构函数中,对象的类型是构造函数或析构函数的类,即使它最终成为一个更派生的类。为此,所有具体的虚函数都被实例化了。

最简单的出路是专门实现DspBuffer&lt;std::complex&lt;double&gt;&gt;::sort(),例如:

template <>
void DspBuffer<std::complex<double>>::sort() {
    std::sort(buf.begin(), buf.end(),
              [](std::complex<double> const& c0, std::complex<double> const& c1) {
                  return c0.real() < c1.real()
                      || (!(c1.real() < c0.real()) && c0.imag() < c1.imag());
              });
}

我不喜欢只有在调用时才断言的函数,特别是如果可以提供一个完美可行的实现:仅仅因为小于运算符对数学公理没有意义意味着复数不能按顺序排序。

【讨论】:

  • 感谢术语更正以及有关如何调用基类方法的提示- 不知道这一点。我明白你关于排序标准有些武断的观点,但我认为更简洁的解决方案是让基类只定义适用于实数和复数的那些方法,并在派生类中添加更专业的方法。再次感谢。
【解决方案2】:

问题是没有为std::complex&lt;T&gt;定义operator &lt;,而std::sort需要定义这个操作。

http://en.cppreference.com/w/cpp/numeric/complex

【讨论】:

  • 是的,我明白这一点。我的问题更多的是为什么要编译基类的排序方法?
  • 为什么你会认为模板的实例化意味着函数不会被编译?您是否对 link time 消除未调用的函数感到困惑?
  • 是的,我想你是对的,修剪会在链接时发生。
猜你喜欢
  • 2015-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多