【问题标题】:Is it reasonable to return a pointer from an overloaded arithmetic operator declared in an abstract class?从抽象类中声明的重载算术运算符返回指针是否合理?
【发布时间】:2012-01-27 20:54:52
【问题描述】:

我有几个纯虚拟课程,MatrixVector。在我的代码库中,我尝试只创建对它们的依赖,而不是它们的具体子类,例如SimpleTransformationMatrix44SimpleTranslationVector4。这样做的动机是我可以使用第三方(改编的)类来代替我的类,而不会有太多麻烦。

我想重载算术运算符(来自here):

T T::operator +(const T& b) const;
T T::operator -(const T& b) const;
T T::operator *(const T& b) const;

我想在纯虚拟类中声明它们,以便对它们的引用/指针执行操作是有效的,问题是抽象类不能按值返回。我能想到的最佳解决方案是这样的:

std::unique_ptr<T> T::operator +(const T& b) const;
std::unique_ptr<T> T::operator -(const T& b) const;
std::unique_ptr<T> T::operator *(const T& b) const;

允许这样做(没有向下转换!):

std::unique_ptr<Matrix> exampleFunction(const Matrix& matrix1, const Matrix& matrix2)
{
    std::unique_ptr<Matrix> product = matrix1 * matrix2;
    return std::move(product);
}

在这种情况下,指针似乎是唯一的选择,因为返回一个值是无效的,而返回一个引用是很愚蠢的。

所以我想我的问题是:我是不是带着这个想法跑题了?如果你在一些你正在编写的代码中看到它,你会自己想 WTF 吗?有没有更好的方法来实现这一点?

【问题讨论】:

    标签: c++ pointers operators overloading


    【解决方案1】:

    首先:重载运算符最适用于值类型。正如您所发现的,多态性并不能很好地发挥作用。不过,如果您愿意拄着拐杖走路,这可能会有所帮助:

    如果您遵循Stackoverflow's operator overloading FAQ 的建议,您将在operator+=() 之上以非成员身份实现operator+()。后者返回一个引用。这仍然是一个问题,因为它只能返回一个基类引用,但只要你只将它用于期望的表达式,你就可以了。

    如果你然后模板化operator+()as DeadMG suggested,你也许可以做你想做的事:

    template<typename T>
    T operator+(const T lhs, const T& rhs)
    {
      lhs += rhs;
      return lhs;
    }
    

    请注意,这将捕获任何T,因为找不到更好匹配的operator+() 重载。 (这似乎是个好主意——直到您忘记包含标头并且此运算符捕获x+y,使代码编译,但默默地产生错误结果。)所以您可能想要限制这一点。

    一种方法是将其放入与矩阵和向量类型相同的命名空间中。或者你使用static_assert 来确保只传入从两者派生的类型。

    【讨论】:

    • 抱歉重播晚了,我想了一会儿。由于您所说的原因,我不确定我是否喜欢模板化operator+()(我没有意识到这是 DeadMG 所说的)。我想我将只使用常规方法而不是运算符,这样我就不会破坏重载约定。谢谢!
    【解决方案2】:

    我是不是带着这个想法跑题了?

    是的。这个问题的适当解决方案是通过模板实现灵活性,而不是继承。继承绝对不适合这种问题。此外,通常(如果没有强制要求)将向量或矩阵的维度另外指定为模板参数,而不是在运行时指定。

    【讨论】:

    • MatrixVector 实际上是模板,但我省略了这些细节以使我的示例更简单。它们将数据类型(例如浮点数)和大小作为模板参数。我倾向于更改Matrix 以获取尺寸。如何通过模板实现灵活性?
    猜你喜欢
    • 2016-07-15
    • 2015-08-12
    • 2021-11-13
    • 2012-09-08
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 2018-02-22
    • 1970-01-01
    相关资源
    最近更新 更多