C++我能正确理解多态性吗

C++ Do I Understand Polymorphism Correctly?

本文关键字:多态性 正确理解 C++      更新时间:2023-10-16

Bar和Box是Foo的派生类,Foo有一个虚拟函数F((,Bar和Box都有函数F(((。据我所知,多态性正确地允许Bar.F((而不是Box.F(。它是这样的:

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

最后一行将调用右F(((在本例中为Box.F(((,而与boxxy是Box、Bar还是Foo无关(在这种情况下,调用虚拟Foo.F的实现(。

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

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

      Foo
     /   
   Bar   Box

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

Bar* barry = new Box();

您将得到一个很好的编译器错误,因为Box无法转换为Bar。:(
所以只有Foo<->BarFoo<->Box,而不是Bar<->Box。接下来,当boxxyBox指针时,它将只调用Box::F函数(如果提供的话(
最后,为了强制子类实现某个函数,您将其声明为pure virtual,如下所示:

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

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

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

如果boxxy是一个Box指针,你只能调用它的F((或它的派生类之一的F(((,除非你对它的父类进行dynamic_cast,然后调用F((。

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

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

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

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

如果派生类没有F((的重写?

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

最后,为了避免实施函数,但仍然允许多态性,你只是写吗空函数体并声明它事实上的

它会起作用,但这不是实现多态性的正确方法。如果你不能为基类的虚拟函数找到一个具体的实现,那么就不要把它实现为空函数。

如果您像这个一样声明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((。

  • 我理解得对吗?是,如果函数被声明为虚拟函数
  • 如果boxxy是一个Box,会发生什么变化指针?取决于函数是否为虚拟函数。虚拟函数最终总是调用适当的导出函数;一非虚拟函数将调用基于的类型的版本指针
  • 如果派生类没有F((的重写?它将使用基类定义
  • 最后,为了避免实施函数,但仍然允许多态性,你只是写吗一个空函数体并声明它事实上的你也可以声明它是纯净的虚拟:CCD_ 14。任何打算实例化的类到一个对象中,可以覆盖这个函数并赋予它适当的执行