【问题标题】:C++ Do I Understand Polymorphism Correctly?C++ 我是否正确理解多态性?
【发布时间】:2011-08-05 15:54:06
【问题描述】:

Bar 和 Box 是 Foo 的派生类,Foo 具有虚函数 F(),Bar 和 Box 都具有函数 F()。据我了解,多态性正确地允许 Bar.F() 而不是 Box.F() 或 Box.F() 而不是 Bar.F() 使用一些运行时例程覆盖 Foo.F() 而不知道您的对象是否是一个酒吧或一个盒子。是这样的:

Foo * boxxy = new Box;
boxxy->F();

最后一行将调用正确的 F()(在本例中为 Box.F()),与 boxxy 是 Box 还是 Bar 或 Foo 无关(在这种情况下,虚拟 Foo.F( ) 被调用)。

我理解对了吗?如果 boxxy 是 Box 指针,会发生什么变化?如果派生类没有覆盖 F() 会发生什么?最后,为了避免为基类实现一个函数但仍然允许多态性,你是否只是编写一个空函数体并将其声明为虚拟?谢谢。

【问题讨论】:

    标签: c++ polymorphism derived-class overriding


    【解决方案1】:

    几乎正确 - 考虑这个继承树:

          Foo
         /   \
       Bar   Box
    

    如果你现在做一个这样的指针:

    Bar* barry = new Box();
    

    您将获得nice compiler error,因为Box 无法转换为Bar。 :)
    所以只有Foo<->BarFoo<->Box,绝不是Bar<->Box。 接下来,当boxxyBox 指针时,它只会调用Box::F 函数,如果它提供的话。
    最后,为了强制子类实现某个功能,你声明它pure virtual,像这样:

    virtual void Func() = 0;
    //   note this --- ^^^^
    

    现在的子类(在本例中为BarBox),必须实现Func,否则它们将无法编译。

    【讨论】:

    • 非常感谢。只是出于好奇,您可以使用 NULL 代替 0 对吗?
    • @Brandon:不,不是在声明纯虚函数时。所需的 exakt 令牌是 =0,仅此而已。另外,我鼓励您使用0 而不是NULL,当C++0x 出现时,使用nullptr 作为指针。 :)
    【解决方案2】:

    如果你这样声明 Foo

    class Foo
    {
    private:
      Foo() {};
    public:
      void func() const { std::cout << "Calling Foo::func()" << std::endl; }
    };
    

    和这样的酒吧

    class Bar : public Foo
    {
    private:
      Bar() {};
    public:
      void func() const { std::cout << "Calling Bar::func()" << std::endl; }
    };
    

    然后

    Foo* bar = new Bar();
    bar->func();
    

    将调用 Foo::func()。

    如果你这样声明 Foo

    class Foo
    {
    private:
      Foo() {};
    public:
      virtual void func() const { std::cout << "Calling Foo::func()" << std::endl; } // NOTICE THE virtual KEYWORD
    };
    

    然后

    Foo* bar = new Bar();
    bar->func();
    

    将调用 Bar::func()。

    【讨论】:

      【解决方案3】:

      如果 boxxy 是 Box 会发生什么变化 指针?

      它将允许访问不是从 Foo 继承的 Box 的方法。 Box 指针不能指向 Bar 对象,因为 Bar 不是从 Box 派生的。

      如果派生类会发生什么 没有对 F() 的覆盖?

      它将从基类继承 F() 的实现。

      最后,为了避免实施 基类的功能,但仍然 允许多态,你只写 一个空的函数体并声明它 虚拟的?

      它会起作用,但它不是做多态性的正确方法。如果你不能为基类的虚函数想出一个具体的实现,使这个函数成为纯虚函数,不要把它实现为空函数。

      【讨论】:

        【解决方案4】:

        是的,将根据您通过 Foo 指针创建的对象类型调用正确的 F()。

        如果 boxxy 是一个 Box 指针,您只能将其称为 F() 或其中一个派生类的 F(),除非您对其父类进行了 dynamic_cast 然后调用 F()。

        为了避免必须在基类中实现,您将其定义为 pure virtual,如下所示:

        class Foo
        {
        public:
            virtual void F() = 0; //notice the = 0, makes this function pure virtual.
        
        };
        

        【讨论】:

          【解决方案5】:
          • 我理解正确吗?是的,如果函数被声明为虚函数。
          • 如果 boxxy 是 Box 会发生什么变化 指针?取决于是否 功能是虚拟的与否。一个虚拟的 函数总是会调用 适当的派生函数;一种 非虚函数将调用 基于类型的版本 指针。
          • 如果派生类会发生什么 没有 F() 的覆盖?它 将使用基类定义。
          • 最后,为了避免实施 基类的功能,但仍然 允许多态,你只写 一个空的函数体并声明它 虚拟的?你也可以声明它是纯的 虚拟:virtual void F() = 0。任何 打算实例化的类 进入一个对象,大大覆盖这个 功能并给它一个适当的 实施。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-04-29
            • 1970-01-01
            • 2011-05-05
            • 2020-11-22
            • 2011-01-29
            相关资源
            最近更新 更多