【问题标题】:passing derived object as base class reference parameter将派生对象作为基类引用参数传递
【发布时间】:2015-07-21 22:38:07
【问题描述】:

这个例子展示了一个派生类对象被传递给一个函数,该函数将基类的引用作为参数。派生类中的成员函数g(int) 隐藏了基类中的g(float)。我明白这一点,我的问题与此无关。

class Base {
public:
    virtual void g(float x) throw()
    {
        cout << "Base::g(float)\n";
    }
};

class Derived : public Base {
public:        
    virtual void g(int x) throw() // Bad: Hides Base::g(float)
    {
        cout << "Derived::g(int)\n";
    }
};


void sampleTwo(Base& b, Derived& d)
{
    b.g(3.14f);
    d.g(3.14f); // Bad: Converts 3.14 to 3 and calls Derived::g(int)
}

int main()
{
    Derived d;
    sampleTwo(d, d);
    return 0;
}

输出是:

Base::g(float)
Derived::g(int)

我的问题是输出“Base::g(float)”。由于sampleTwo()中'b'引用的对象是派生对象,难道动态绑定不应该调用派生类的g()方法(将float转为int)吗?

【问题讨论】:

  • 在编写派生类的函数来覆盖基类的虚函数时,最好开始使用override 关键字(假设编译器具有合理的 C++11 支持)。这样,如果函数实际上没有按照您的预期覆盖,编译器就会给您一个错误。
  • 我也很惊讶,但我最初的猜测是看到 base::g(float) 调用了两次,而不是 derived::g(int),因为这两种情况下的函数调用都匹配g(float) 的签名,它是与 g(int) 不同的函数(这是两个不同的函数,您的代码不会进行任何覆盖)
  • 您应该在Derived 中执行using Base::g 以取消隐藏Base::g(float)

标签: c++ dynamic-binding


【解决方案1】:

g(int)g(float) 是两种完全不同的方法。 Derived::g(int) 不会覆盖 Base::g(float)。这些方法是不相关的。

由于Derived 不会覆盖g(float),您对b.g(3.14f) 的期望是没有根据的。正如预期的那样,b.g(3.14f) 应该调用 Base::g(float)

如果你在Derived 中覆盖g(float),那么b.g(3.14f) 确实会调用Derived::g(float)

【讨论】:

    【解决方案2】:

    动态调度调用最终覆盖器。由于Derived::g 隐藏而不是覆盖Base::g,所以DerivedBase::g 的最终覆盖者仍然是Base::g

    【讨论】:

      【解决方案3】:

      g(float)g(int) 是不同的函数成员。如果你想让Derived 工作,你必须在两个类中都使用g(float)

      g()可以重载检查函数重载: https://en.wikipedia.org/wiki/Function_overloading

      示例(g(float)g(int) 在同一个类和不同的函数中):

      class Derived : public Base {
      public:
      
          void g(float x) throw();
          void g(int x) throw();
      
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-01
        • 1970-01-01
        • 2022-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多