【问题标题】:Operator + overloading in base class and using it in derived class基类中的运算符 + 重载并在派生类中使用它
【发布时间】:2015-07-20 04:58:45
【问题描述】:

我有 2 个类,基类(带有复制构造函数)和派生类,在基类中我重载了 operator+

class Base {

  public:

     Base(const Base& x) {
         // some code for copying
     }

     Base operator+(const Base &bignum) const {
         Base x;
         /* ... */
         return x;
     }
};

class Derived : public Base {
};

当我尝试做类似的事情时

Derived x;
Derived y;
Derived c=x+y;

我收到错误:conversion from "Base" to non-scalar type "Derived" derived 问题可能出在那个运算符 + 返回Base 类型的对象,我想将它分配给Derived 类型的对象?

【问题讨论】:

  • 是的,这正是作业,而且只是作业。您所需要的只是一个构造函数,用于解释编译器如何将 Base 放入 Derived 而不会造成伤害。

标签: c++ inheritance operator-overloading


【解决方案1】:

事实上,您不需要重新定义 operator+(除非您的设计需要它,正如 Ajay 的示例所指出的那样)。

效果比你想象的要好

举个简单的例子:

struct Base {
    Base operator+ (Base a) const
        { cout <<"Base+Base\n"; }
    Base& operator= (Base a)  
        { cout<<"Base=Base\n"; }
};
struct Derived : public Base { };

int main() {
    Base a,b,c;  
    c=a+b;     // prints out "Base+Base" and "Base=Base"
    Derived e,f,g; 
    e+f;       // prints out "Base+Base" (implicit conversion); 
}  

这很有效,因为当遇到e+f 时,编译器会找到基类的operator+,然后他隐式地将Derived 转换为Base,并计算出Base 类型的结果。你可以很容易地写c=e+f

缺少什么?

问题仅始于派生分配。只要你尝试g=e+f;,你就会得到一个错误。编译器不确定如何将 A 放入 B。这种谨慎是由常识证明的:所有的猿都是动物,但所有的动物都不一定是猿

如果Derived 的字段比Base 多,这一点就更加明显:编译器应该如何初始化它们?基本上,如何告诉编译器他应该如何用其他东西制作Derived?使用构造函数!

struct Derived : public Base {
    Derived()=default; 
    Derived(const Base& a) : Base(a) { cout<<"construct B from A\n"; }
};

一旦你定义了这个,一切都会如你所愿:

 g=e+f;   // will automatically construct a Derived from the result
          // and then execute `Derived`'s default `operator=` which 
          // will call `Base`'s `operator=`  

这里是live demo

【讨论】:

  • 谢谢!在这个问题上卡了一段时间,这已经解释清楚了,你的答案很完美。
【解决方案2】:

这不是一个正确的设计。考虑具有xy 的类Point2D,以及继承自Point2D 的具有附加成员zPoint3D 类。你的事情会有所帮助吗?

Point2D operator+(const Point2D &pt) const;

调用时:

Point3D a, b;
Point3D c = a+b;

?

【讨论】:

  • 是的,我知道,但在这种情况下,我的 Derived 类只给了我几个方法,没有新变量,那么这样使用有什么问题?很抱歉没有提及这一点。
  • 但这不会安抚编译器。虚拟功能可能是障碍,如果有的话。您可以在基类中私下编写BaseToDerived 函数。在Derived 中编写所有此类函数,这将调用base' 版本(并获得Base)。然后调用这个(私有)函数返回Derived
  • 我不明白我为什么要那样做?
  • 例如,用于在Derived 类中实现operator+,以便Derived 的任何用户都可以调用它而不会遇到警告。并重新使用相同的基本实现。
  • 就像我说的 Derived 类中唯一的方法是重载的 operator/ 和 operator* 。如果我做了 operator+,那么拥有 2 个班级会有什么意义。我知道这是个奇怪的问题,但这是大学的问题。
【解决方案3】:

是的,这正是问题所在。加号运算符只保证返回一个 Base 对象,因此您可以将其分配给 Base 对象。所有 Derived 对象都可以替换为 Bases,但不能以其他方式替换。

【讨论】:

  • 好的,那么通过在Derived 类中创建复制构造函数来解决这个问题,它采用Base 类型对象,并执行类似的操作:Derived(const Base&amp; x) :Base(x) {} ??
  • 这可行,但它暗示了代码设计方式可能存在更大的问题(可能滥用继承)。奇怪的是,Base 对象中包含成为 Dervied 对象所需的所有信息。
  • 这只是学术问题,我们必须做派生类,只有少数方法,没有新变量。
  • 问题的陈述是什么?
  • 我的课程在 bcd 中保存了大量的数字。在这个基类中,我重载了operator+operator-。现在我必须为这个 Bignum 类创建派生类,其中将重载 operator*operator/
猜你喜欢
  • 1970-01-01
  • 2011-08-06
  • 2015-01-20
  • 1970-01-01
  • 2020-04-04
  • 2013-12-17
  • 2012-01-15
相关资源
最近更新 更多