c++ - 将多态与 operator+ 重载模板类一起使用。如何实现基类?

标签 c++ templates polymorphism

我正在尝试为不同大小的矩阵和 vector 创建模板类。 对于我的 Vector 类,我重载了 += 和 + 运算符,以便能够添加两个相同长度的 vector 。如果长度不匹配,我希望编译器抛出错误。

我想在 std::vector 中存储多个 mvc::Vector 对象(具有不同的长度)。

为此,我创建了一个基类 mvc::VectorBase,我从中继承了所有 mvc::Vector 对象。

现在我可以写了

std::vector<std::unique_ptr<mvc::VectorBase>> vectorBuffer;

为了能够从 vectorBuffer 调用 MyVector 的成员函数,我为这些成员添加了纯虚函数,以便我可以使用

vectorBuffer[0]->GetLength().

我的问题:我无法编写代码,因为 VectorBase 不知道运算符重载。

mvc::Vector<2> result = (*vectorBuffer[0]) + (*vectorBuffer[1]);

尝试将运算符重载作为纯虚拟添加到 mvc::VectorBase 没有成功,因为一个参数必须是来自 mvc::Vector 模板类的模板参数,我不能在模板之外使用它。

#include <vector>
#include <memory>

#define T float

namespace mvc
{
    class VectorBase
    {
    public:
        // virtual Vector operator+= (Vector<Tlength>& other) = 0;
        virtual int GetLength() const = 0;
    };

    template<int Tlength>
    class Vector : public VectorBase
    {
    private:
        T vec[Tlength];

    public:
        Vector operator+ (Vector<Tlength>& other)
        {
            for (int i = 0; i < Tlength; i++)
            {
                vec[i] += other.vec[i];
            }
            return *this;
        }

        int GetLength() const
        {
            return Tlength
        }
    }
}

int main()
{
    mvc::Vector<3> vec3_1;
    mvc::Vector<3> vec3_2;
    mvc::Vector<4> vec4_1;

    mvc::Vector<3> result = vec3_1 + vec3_2; // this line works properly 
    mvc::Vector<3> result = vec3_1 + vec4_1; //this line won´t compile (as expected)

    std::vector<std::unique_ptr<mvc::VectorBase>> vectorBuffer;

    vectorBuffer.push_back(std::make_unique<mvc::Vector<2>>());
    vectorBuffer.push_back(std::make_unique<mvc::Vector<2>>());

    mvc::Vector<2> result = (*vectorBuffer[0]) + (*vectorBuffer[1]); // <-- this is what i want to be able to do
}

如何实现所需的行为?

vectorBuffer[0] + vectorBuffer[1] 只有在使用相同模板生成 MyVector 对象(Tlength 相等)时才有效

这已经适用于两个单独存储的 MyVector 实例。

当我使用多态性将多个 mvc::Vector 对象存储在同一个 std::vector 中时失败。

编辑:

通过以基类作为返回类型重载 + 运算符,我得到了请求的行为:

#include <vector>
#include <memory>
#include <iostream>

#define T float

namespace mvc
{
    class VectorBase
    {
    public:
        virtual VectorBase* operator+ (VectorBase& other) = 0;
        virtual int GetLength() const = 0;
        virtual T GetElem(int i) const = 0;
        virtual void Print() const = 0;
    };

    template<int Tlength>
    class Vector : public VectorBase
    {
    private:
        T vec[Tlength];

    public:
        Vector(T initValue)
        {
            for (int i = 0; i < Tlength; i++)
            {
                vec[i] = initValue;
            }
        }

        VectorBase* operator+ (VectorBase& other) override
        {
            if (other.GetLength() != Tlength)
            {
                std::cout << "[Error]: Argument dimensions mismatch. Program will terminate." << std::endl;
                std::cin.get();
                exit(-1);
            }

            //Vector<Tlength> tmpOther = dynamic_cast<Vector<Tlength>&>(other);

            for (int i = 0; i < Tlength; i++)
            {
                //vec[i] += tmpOther.vec[i];
                vec[i] += other.GetElem(i);
            }
            return this;
        }


        Vector<Tlength> operator+ (Vector<Tlength>& other)
        {
            for (int i = 0; i < Tlength; i++)
            {
                vec[i] += other.GetElem(i);
            }
            return *this;
        }

        int GetLength() const override
        {
            return Tlength;
        }

        T GetElem(int i) const override
        {
            return vec[i];
        }

        void Print() const override
        {
            for (int i = 0; i < Tlength; i++)
            {
                std::cout << " " << vec[i] << "\n";
            }
            std::cout << std::endl;
        }
    };
}

int main()
{
    /* without polymorphism */
    // vector1
    mvc::Vector<2> vec3_1 = mvc::Vector<2>(1.2f);
    vec3_1.Print();
    // vector2
    mvc::Vector<2> vec3_2 = mvc::Vector<2>(3.4f);
    vec3_2.Print();
    // vector2 = vector1 + vector2
    vec3_2 = vec3_1 + vec3_2;
    vec3_2.Print();

    /* with polymorphism */
    // vector buffer storing base class objects
    std::vector<mvc::VectorBase*> vectorBuffer;
    //vector1
    vectorBuffer.push_back(new mvc::Vector<3>(3.5f));
    vectorBuffer[0]->Print();
    //vector2
    vectorBuffer.push_back(new mvc::Vector<3>(2.8f));
    vectorBuffer[1]->Print();
    //vector2 = vector1 + vector2
    vectorBuffer[1] = *vectorBuffer[0] + *vectorBuffer[1];
    vectorBuffer[1]->Print();

    std::cin.get();

    for (unsigned int i = 0; i < vectorBuffer.size(); i++)
    {
        delete vectorBuffer[i];
    }
}

plus 运算符重载了两次,以支持“非多态”用法。 (参见 main 中的示例)

在 operator+ override 内部是一个使用 @Vikas Awadhiya 的 dynamic_cast 解决方案的推荐。这也有效。目前我不知道与我当前使用虚拟 getter 函数 GetElem 的解决方案相比的性能。

现在我只能让它与原始指针一起工作。仍在研究 unique_ptr 解决方案。

感谢大家的回复!

最佳答案

你可以通过让你的虚拟 operator+ 返回并接受基类来做到这一点:

class VectorBase
{
public:
    virtual int GetLength() const = 0;
    // We have to return a heap allocated object because the actual type and,
    // hence, its size is unknown
    virtual std::unique_ptr<VectorBase> operator+(VectorBase& other) = 0;
};

template<int Tlength>
class Vector: public VectorBase
{
private:
    // ...

    std::unique_ptr<VectorBase> operator+(VectorBase& other) override
    {
        if (other.GetLength() != Tlength)
            return nullptr; // or throw an exception if you want

        Vector result = *this + static_cast<Vector<Tlength>&>(other);
        // or "new Vector<Tlength>(result)" if your compiler doesn't support C++14
        return std::make_unique<Vector<Tlength>>(result);
    }

    // ...
};

关于c++ - 将多态与 operator+ 重载模板类一起使用。如何实现基类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56706314/

相关文章:

c++ - 错误 C3861 : 'strcpy_y' : identifier not found

Java 类内部泛型绑定(bind)掩盖了父接口(interface)泛型绑定(bind)定义

c++ - 为了获得性能而避免多态性是否值得?

c++ - 斐波那契数列 : Elements do not make sense when array size > 28

c++ - 动态调度的部分模板特化

c++ - 我们是否需要在 C++ 中进行矢量化,或者 for 循环是否已经足够快?

c++ - 为什么可变参数函数不适用于模板

c++ - 有没有办法检测混合类型和非类型的任意模板类?

java - 在 jar 文件中加载速度模板

java - java继承覆盖变量的解释