【问题标题】:Override a member function with different return type覆盖具有不同返回类型的成员函数
【发布时间】:2012-02-16 13:07:33
【问题描述】:

考虑下面的例子:

#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 在派生类中被重新定义,并具有不同的返回类型。但是编译器会抛出错误。我的理解正确吗?

【问题讨论】:

  • 为了澄清,什么编译器给你什么错误?
  • @SionSheevok,GCC 至少:codepad.org/z7rXpCeK
  • @SionSheevok :我正在使用 gcc 3.4.6
  • 点头我并不是说它不会出错,只是好奇编译器具体试图传达什么。

标签: c++ virtual-functions overriding redefinition


【解决方案1】:

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

为了实现这一点,唯一可能的方法是限制覆盖虚拟方法的返回类型,使其返回与基类相同的类型或派生自基类的类型(协变返回类型),标准强制执行此操作健康)状况。

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

【讨论】:

  • Als:type derived from that(co-variant return types)。这对我的理解至关重要。很好的解释。 :)
【解决方案2】:

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

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

【讨论】:

  • Note that if you change part of the signature (parameters, const-ness, etc), then you can change the return value as well。如果我这样做,那么该功能不会被覆盖对吗?
  • 完全一样或子类,我想你的意思是。
  • co-variant 允许虚函数返回类型。
  • @LinuxPenseur,正确,如果签名更改,该函数不会被覆盖
  • @Als:为了强调,我们可以为您提供我们别致的斜体,而这只是在,bold脸?
【解决方案3】:

this question。总而言之,如果类型为covariant,则只能使用不同的返回类型覆盖虚函数。

【讨论】:

  • types 不是协变的,override 是。
  • 不,只是你对它的解释有点特殊。
【解决方案4】:

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

请参阅以下内容:

#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.;

      }
};

【讨论】:

    【解决方案5】:

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

    【讨论】:

    • 这里的签名是一样的。这些函数仅在返回类型上有所不同,并且返回类型不是签名的一部分。
    • @LinuxPenseur 谢谢你告诉我,这就是我的意思
    • 当覆盖一个方法时,只要这个改变不与声明的方法冲突(类型是协变的),就可以改变返回类型。这不会破坏多态性,因为覆盖的协变类型也是方法声明的有效类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 1970-01-01
    • 2018-02-14
    • 1970-01-01
    相关资源
    最近更新 更多