【问题标题】:Polymorphism is not working with function return values of same data type (Base and Inherited class)多态性不适用于相同数据类型(基类和继承类)的函数返回值
【发布时间】:2015-03-21 03:50:21
【问题描述】:

据我所知,要在继承类中覆盖虚函数,该函数应该具有与基类函数相同的返回值数据类型。

但是如果你返回一个指针或值,它属于从原始函数的返回值的类继承的类,编译器将接受更改返回值,如下所示:

#include <iostream>

class Base{
public:
virtual  Base * clone() {
    std::cout << "Base::clone()\n" ;
    Base * bp = new Base ;
    return bp ;
}
  std::string ID() {return "Base class";}
};

class Derived: public Base {
public:
  //Derived* and Base* are same data type (acceptable):
  Derived * clone() {
    std::cout << "Derived::clone()\n" ;
    Derived * dp = new Derived ;
    return dp ;
}
  std::string ID() {return "Derived class";}
};


int main() {

  Base * bp = new Derived;

  std::cout << bp->clone()->ID() <<"\n";

  std::cout << dynamic_cast <Derived*>(bp->clone())->ID() <<"\n";
  /*
  next code give error: cannot convert Base* to Derived*: 

  Derived * dp2 = bp->clone();
  std::cout << dp2->ID() << "\n";
  */
}

g++ 的输出是:

Derived::clone()
Base class
Derived::clone()
Derived class

Derived 类中重写的 clone() 函数返回指向堆上相同对象副本的指针。从输出中可以看出,每次都会调用正确版本的clone(),但不会调用ID()。为了解决这个问题,我不得不通过dynamic_cast 或在基类中制作virtual ID() 来降低返回值以获得所需的效果。

我的问题:为什么多态性在第一种情况下不起作用

  std::cout << bp->clone()->ID() <<"\n";

因为clone() 应该从Derived 类返回一个指向对象的指针,因此Derived 类的ID() 函数不是Base 类,但在这种情况下我有@ 的ID() 函数987654336@班级?

【问题讨论】:

  • 您是否忘记了 Base::ID 前面的virtual?目前它不是一个多态函数。
  • 不,正如我在问题中所说,我已经测试了这个选项。其实我本来打算不使用 virtual 关键字来测试 ID() 的输出。
  • 但是你的问题是为什么多态性在没有的情况下不起作用。原因是ID函数不是虚拟的。
  • 如果你说它的类型是Base,编译器应该如何知道bp是否是Derived?显然,一切都很清楚,因为您调用 clone 就好像它是基类的方法一样。
  • 我的问题是 clone() 将返回 Derived* 指针,所以当我调用 clone()->ID 为什么返回值被视为 Base* 指针。那么我为什么要使用 virtual 呢?

标签: c++ inheritance polymorphism


【解决方案1】:

在这种情况下,多态性正常工作。代码在您期望 Derived class 时打印 Base class 的原因是因为 ID() 方法不是 virtual

为了了解会发生什么,您必须将代码视为编译器。在您的示例中,bp 是指向 Derived 实例的指针,但在代码中它已被键入为 Base *,因此编译器会看到 Base *。当编译器稍后在代码中看到bp-&gt;clone() 时,它知道Base 类的clone() 方法返回Base *。最后,当编译器到达-&gt;ID() 方法调用时,它会查看Base 类定义并看到一个非虚拟 方法,因此它确保在运行时调用Base::ID() 方法那个位置。

如果您想要多态行为,请为两个 ID() 方法添加 virtual 关键字。如果您使用符合 C++2011 的编译器,还可以在 Derived::ID() 上添加 override 关键字。

【讨论】:

  • 我不清楚的是:bp-&gt;clone() 执行虚拟调度,因此它通过Base* 指针调用Derived::clone(),这里没什么特别的。但是后者返回一个Derived*,所以bp-&gt;clone()的返回类型应该是Derived*。其实不是,是Base*,这是为什么呢?
  • 编译器在编译时无法知道clone() 调用将返回一个Derived*,因此它会按照变量bp 的定义进行。
  • @vsoftco 没错,这就是我的问题的意思
  • @vsoftco 虚拟调度意味着编译器在编译时不知道clone() 函数将返回什么类型,只知道它将是Base* 的派生。编译器可以跟踪 clone() 返回的正确类型的唯一方法是通过虚拟调度,并且只有在 ID() 也被声明为虚拟时才会发生这种情况。
  • @Galik,这是有道理的,但是引入这种时髦的协变返回类型的全部原因是什么?我的意思是,与简单地写 Base* Derived::clone() override 相比有什么优势?
猜你喜欢
  • 2016-09-13
  • 2017-10-21
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多