在继承类中使用基类定义的运算符

问题描述 投票:0回答:1

假设我有一个基类

class Vector
{
public:
    Vector(const std::vector<float> &elements);

    static Vector add(const Vector &v1, const Vector &v2);

    Vector Vector::operator+(const Vector &v) const
    {
        return add(*this, v);
    }

    Vector &Vector::operator+=(const Vector &v)
    {
        *this = add(*this, v);
        return *this;
    }

    float operator[](size_t index) const;

private:
    std::vector<float> _elements;
}

以及 3 元素向量的派生类

class Vector3 : public Vector
{

public:

    Vector3(float x, float y, float z);
};

我必须做什么才能将运算符与派生类一起使用?

我的解决方案是重新定义派生类中的运算符,如下所示:

Vector3 Vector3::operator+(const Vector3 &v) const
{
    Vector res = Vector::operator+(v);
    return Vector3(res[0], res[1], res[2]);
}

Vector3 &Vector3::operator+=(const Vector3 &v)
{
    Vector res = Vector::operator+=(v);
    *this = Vector3(res[0], res[1], res[2]);
    return *this;
}

到目前为止,这是可行的,但我想知道这是否是正确的方法。对我来说,这看起来很像双重工作。此外,我不完全理解为什么我必须首先重新定义运算符。是因为我无法从 Vector 转换为 Vector3 吗?我的简单假设是“Vector3”与大小为 3 的“Vector”相同,因此在我看来,不存在与给定操作员任务不同相关的差异。如果有人能启发我是否有更好的方法,那就太好了。

c++ class inheritance operators
1个回答
0
投票

框架挑战:您想要在这里做的事情增加了复杂性、继承性和您必须跳过的障碍(实践和概念),并降低了性能。由于您通常只想承受增加的复杂性以获得更高的性能,因此请做其他事情。

我的建议是,记住你的大部分想法是

  1. Vector
    转换为模板,其大小是模板参数(并且可能存储数据类型,以便您可以轻松地在
    float
    double
    int
    之间切换)
  2. Vector3
    转换为 typedef。例如
    using Vector3 = Vector<3>;
    。现在
    Vector3
    字面上是
    Vector
    ,因此无需在继承中纠结,同时提供您想要的行为。
  3. 使运算符重载更加惯用。

这是一个快速演示:

#include <array>
#include <cstddef>
#include <functional>
#include <algorithm>
#include <iostream>

template<size_t SIZE> // A more general <class TYPE, int SIZE> will be more useful
class Vector
{
public:
    // initializer_list may make this easier to work with
    Vector(const std::array<float,SIZE> &elements): _elements(elements)
    {

    }

    Vector & operator+=(const Vector &v)
    {
        //just crapping out a simple summation here for demo purposes
        std::transform(_elements.begin(), _elements.end(),
                       v._elements.begin(),
                       _elements.begin(),
                       std::plus());
        return *this;
    }

    float operator[](size_t index) const;
    // consider adding the usual iterator -granting functions so 
    // you can use one of these in Standard algorithms

    // added for demo purposes to print out the result
    friend std::ostream & operator<<(std::ostream & out,
                                     const Vector & vec)
    {
        for (const auto & val:vec._elements)
        {
            out << val << ' ';
        }
        return out;
    }

private:
    std::array<float, SIZE> _elements; // Look ma! No pointers! 
                                       // The Vector data is IN the Vector!
                                       // no extra look-ups and no extra 
                                       // cache misses
};


// now a free function to aid in decoupling 
template <size_t SIZE>
Vector<SIZE> operator+(Vector<SIZE> lhs, 
                       const Vector<SIZE> &rhs)
{
    lhs += rhs;
    return lhs;
}

using Vector3 = Vector<3>;

int main()
{
    Vector3 a({1,2,3});
    Vector3 b({3,2,1});
    Vector3 c = a+b;

    std::cout << c << '\n';

    Vector<4> d({});

    //Vector3 e = c+d; // addition fails at compile time because the types 
                       // don't match. Much debug savings
}
© www.soinside.com 2019 - 2024. All rights reserved.