27

考虑下面的例子:

#include <iostream>

using namespace std;

class base
{
   public:
      virtual int func()
      {
         cout << "vfunc in base class\n";
         return 0;
      }
};

class derived: public base
{
   public:
      double func()
      {
         cout << "vfunc in derived class\n";
         return 0;
      }
};

int main()
{
   base *bptr = new derived;
   bptr->func();

   return 0;
}

编译器对上述代码给出了一个错误,即覆盖函数的类型存在冲突。为什么不能用不同的返回类型覆盖派生类中的函数?

我相信,为了重写一个函数,需要在派生类中重新定义基类虚方法。要重新定义方法,方法的签名必须相同。由于返回类型不是签名的一部分,我相信即使返回类型存在差异,方法仍然会被重新定义?func在这种情况下,对于上面的代码,在派生类中用不同的返回类型重新定义了虚函数。但是编译器会抛出错误。我的理解正确吗?

4

5 回答 5

30

重写本质上意味着将在运行时调用基类方法或派生类方法,具体取决于指针指向的实际对象。
这意味着:
即:可以调用基类方法的每个地方都可以通过调用派生类方法来代替,而无需更改调用代码。

为了实现这一点,唯一可能的方法是将覆盖虚拟方法的返回类型限制为返回与基类相同的类型或从该类派生的类型(协变返回类型),并且标准强制执行此条件。

如果上述条件不存在,则会留下一个窗口,通过添加新功能来破坏现有代码。

于 2012-01-23T05:03:32.660 回答
12

为了覆盖虚函数,返回值必须完全相同*。C++不会double在和之间自动转换int——毕竟,当从派生类指针调用时,它怎么知道你想要什么返回类型呢?请注意,如果您更改部分签名(参数、常量等),那么您也可以更改返回值。

* - 严格来说,它必须是“协变的”。这意味着您返回的类型必须是父函数返回类型的子集。例如,如果父类返回 a base *,您可以返回 a derived *。由于deriveds 同时也是bases,编译器允许您以这种方式覆盖。但是您不能返回完全不相关的类型,例如intand double; 仅仅因为有一个隐式转换并不意味着编译器会让你做这种覆盖。

于 2012-01-23T04:54:06.827 回答
8

看到这个问题。总而言之,如果类型是协变的,则只能使用不同的返回类型覆盖虚函数。

于 2012-01-23T04:56:41.490 回答
2

如果你想覆盖,你应该尝试使用模板。

请参阅以下内容:

#include <iostream>

using namespace std;

class base
{
   public:
      template<typename X> X func()
      {
         cout << "vfunc in base class\n";
         return static_cast<X>(0);
      }  
};    

class derived: public base
{
   public:
      template<typename X> X func()
      {
         cout << "vfunc in derived class\n";
         return static_cast<X>(2);
      }  
};    

int main()
{
   derived *bptr = new derived;
   cout << bptr->func<int>() << endl;
   cout << dynamic_cast<base*>(bptr)->func<int>() << endl;

   derived *bptr2 = new derived;
   cout << bptr->func<double>() << endl;
   cout << dynamic_cast<base*>(bptr)->func<int>() << endl;


   return 0;
}

当然,您不需要以这种方式在两个不同的类上声明它,您可以这样做:

class base
{
   public:
      int func()
      {
         cout << "vfunc in base class\n";
         return 0;
      }  

      double func(){
        cout << "vfunc for double class\n";
        return 2.;

      }
};
于 2012-01-23T16:05:46.350 回答
-2

覆盖是不可能的,因为签名是相同的,唯一的区别是返回值。覆盖的基本目的是多态,但在上面的例子中是不可能的

于 2012-01-23T05:01:49.307 回答