вопросы о виртуальной функции в с ++ - PullRequest
6 голосов
/ 06 мая 2011

Я новичок в C ++, сейчас изучаю виртуальные функции.Есть некоторые вопросы, которые меня сильно смущают.

например:

class A {
  public:
  virtual void f() {
      //do something; 
  }
}

class B: public A {
   public:
   virtual void f() {
//do something;
}
}
  1. class A содержит виртуальную функцию f(), а class B наследует ее,Внутри class B функция f() также объявлена ​​как виртуальная, так значит ли это f() в class B перегрузках f() в class A?Позволяет ли классы, которые наследуют B, перегружать f()?Или B определяет новую виртуальную функцию, которая отличается от f() в class A?

  2. Виртуальные функции обеспечивают способ перегрузки методов.Если B наследует A и не объявляет f() как virtual, то может ли класс C, который наследует B, перегрузить f() и достичь полиморфизма?

Ответы [ 4 ]

4 голосов
/ 06 мая 2011

внутри класса B функция f () также объявляется как виртуальная, поэтому это означает, что f () в классе B перегружает f () в классе A

Нет, это не перегрузка . Это переопределяет . Также ключевое слово virtual необязательно в классе B. B::f() всегда будет функцией virtual, независимо от того, пишете вы virtual или нет.

Термин перегрузка используется, когда вы определяете функцию с тем же именем, но различными параметрами. В вашем случае сигнатура функции f одинакова в обоих классах, это означает, что она не перегружает 1024 *; производный класс в основном переопределяет определение базового класса f().

2 голосов
/ 06 мая 2011

Виртуальное ключевое слово позволяет вам переопределить функции, а не перегрузить их.

Кроме того, виртуальный атрибут наследуется, поэтому ключевое слово virtual необязательно для f() в class B.

1 голос
/ 06 мая 2011

Когда вы объявляете функцию виртуальной, вы на самом деле говорите компилятору, что хотите, чтобы эта функция работала полиморфно. То есть из вашего примера, если у нас есть следующее:

A* foo = new B();
foo->f();

он будет вызывать функцию "f" в B, а не функцию "f" в A. Если продолжить, если у нас есть C, который наследует от B, как вы сказали:

class C : public B{}

B* foo = new C();
foo->f():

это вызывает B's "f". Если бы вы определили его в C, он вызвал бы метод C.

Чтобы объяснить различное поведение между виртуальным и не виртуальным, давайте возьмем этот пример:

struct Foo{
    virtual void f();
    void g();
};

struct Bar{
    virtual void f();
    void g();
};

Foo* var = new Bar();
var->f(); //calls Bar's f
var->g(); //calls Foo's g, it's not virtual

имеет смысл?

0 голосов
/ 06 мая 2011

Поскольку A :: f является виртуальным, а B :: f имеет одинаковую подпись , говорят, что B :: f переопределяет A :: f.

Что означает:

A * p = new B;
p->f(); // invokes B::f

РЕДАКТИРОВАТЬ: следующее просто неправильно (см. Комментарии):

Поскольку B :: f также является виртуальным, дочерний класс B мог бы переопределить его снова. Если бы B: f не был виртуальным, то любой метод с такой же сигнатурой в дочернем классе просто затенял бы его (то есть это был бы другой метод).

Итак, поведение зависит от родителя.

...