C++ 运算符重载和继承

Posted

技术标签:

【中文标题】C++ 运算符重载和继承【英文标题】:C++ Operator Overloading and Inheritance 【发布时间】:2014-10-11 14:50:40 【问题描述】:

我将从代码开始,因为它更容易解释。

vector.cpp

template <typename T, unsinged int D>
class Vector

public:
    Vector() 

    inline Vector<T, D> operator+(const Vector<T,D>& r)
    
        Vector<T,D> result = T(0);
        for(int i = 0; i < D; i++)
            result[i] = (*this)[i] + r[i];

        return result;
    
private:
    T values[D];


template <typename T>
class Vector3 : public Vector<T, 3>

   // Initialization constructor etc..


main.cpp

int main(int argc, char** args)

    Vector3<float> vec1 = Vector3<float>(1.0f, 2.0f, 3.0f);
    Vector3<float> vec2 = Vector3<float>(1.0f, 2.0f, 3.0f);
    Vector3<float> res;

    res = vec1 + vec2;    // Here's the error

    return 1;

由于某种原因,我在指示行收到错误消息,指出没有运算符“=”与这些操作数匹配,操作数类型为 Vector3&lt;float&gt; = Vector&lt;float, 3U&gt;。如果我将变量“res”声明为Vector&lt;float, 3&gt; res;,它就可以工作。我不明白为什么会发生这种情况,因为它继承了类“Vector”的定义。有人可以在这里帮助我吗,我最好希望在不必为所有派生类重新编写运算符重载函数的情况下完成这项工作。我也有类似的矩阵实现。

提前谢谢你。

干杯。

【问题讨论】:

基类不能隐式转换为派生类。 调用包含固定大小数组的对象vector 似乎令人困惑。 混合运算符重载和继承几乎总是一个设计错误。 为什么它几乎总是一个设计错误? 【参考方案1】:

这个vec1 + vec2 调用父类的operator+,它返回一个父类类型的对象。您不能将Vector&lt;float, 3U&gt; 的对象分配给Vector3&lt;float&gt; 类型的对象。

int main(int argc, char** args)

    Vector<float, 3U> v;
    Vector3<float> res;

    res = v;    // Here's the error

你可以这样做:

int main(int argc, char** args)

    Vector3<float> vec1 = Vector3<float>(1.0f, 2.0f, 3.0f);
    Vector3<float> vec2 = Vector3<float>(1.0f, 2.0f, 3.0f);

    Vector<float, 3U> res = vec1 + vec2;

我会说尝试使用继承可能不是最好的主意。如果您可以使用 C++11,那么类型别名可能会更好:

template <typename T, unsinged int D>
class Vector

    template<typename... Args> Vector(Args &&...args)
      : valuesstd::forward<Args>(args)...
    
    // ...
;

template<typename T>
using Vector3 = Vector<T, 3>;

我已经重载了 '[]'、'==' 和 '!=' 并且它似乎可以正常工作,

问题在于,使用operator+,您将返回父类型Vector&lt;float,3U&gt;,然后尝试在需要子类型Vector3&lt;float&gt; 的地方使用该类型。

使用operator[],您可能会返回T&amp;,然后在需要T&amp; 的地方使用它。使用operator!=operator==,您将返回bool,并在需要bool 的地方使用它。你看得到差别吗?你明白为什么吗:

Vector3<float> res = Vector3<float>();

工作和

Vector3<float> res = Vector<float, 3U>();

没有?

您能否进一步解释一下什么是类型别名,以及它如何改进上述实现,以及为什么会这样。

您可以在manyplaces 中了解它们的含义。它们对您的使用很重要的是不要创建新类型,它们只是创建一种新方式来引用先前声明的类型。

因此,例如,对于基于 Vector3 的继承,代码 Vector3&lt;float&gt; res = Vector&lt;float, 3U&gt;(); 将失败,但如果 Vector3 是类型别名:

template<typename T> using Vector3 = Vector<T, 3U>;

那么代码Vector3&lt;float&gt; res = Vector&lt;float, 3U&gt;();就会成功,因为左右两边的类型不再不匹配了:使用类型别名意味着Vector3&lt;float&gt;不是从@继承的 987654348@,它类型Vector&lt;float, 3U&gt;

【讨论】:

我已经重载了 '[]'、'==' 和 '!=' 并且它似乎没有问题地工作,为什么这些工作,以及为什么它不适用于算术运算。您能否进一步解释一下什么是类型别名,它如何改进上述实现,以及为什么会这样。

以上是关于C++ 运算符重载和继承的主要内容,如果未能解决你的问题,请参考以下文章

C++ 继承多态关系中的赋值运算符的重载=operator()

C++ 继承多态关系中的赋值运算符的重载=operator()

如何为从C++中的模板继承的类重载赋值运算符

C++ 从类中调用重载运算符

在C++中,啥是运算符重载?啥是虚函数?

逆向第十九讲——类继承和成员类运算符重载模板逆向20171211