C ++ Правильно ли я понимаю полиморфизм? - PullRequest
2 голосов
/ 14 апреля 2011

Bar и Box являются производными классами Foo, а Foo имеет виртуальную функцию F (), а Bar и Box имеют функцию F (). Из того, что я понимаю, полиморфизм правильно позволяет Bar.F () вместо Box.F () или Box.F () вместо Bar.F () переопределять Foo.F () с использованием некоторой подпрограммы времени выполнения, не зная, является ли ваш объект Бар или Коробка. Это примерно так:

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

Последняя строка будет вызывать правильное F () (в данном случае Box.F ()) независимо от того, является ли boxxy Box или Bar или Foo (в этом случае реализация виртуального Foo.F ( ) называется).

Я правильно понимаю? А что изменится, если boxxy будет указателем Box? И что произойдет, если производный класс не имеет переопределения для F ()? Наконец, чтобы избежать реализации функции для базового класса, но при этом разрешить полиморфизм, вы просто пишете пустое тело функции и объявляете его виртуальным? Спасибо.

Ответы [ 5 ]

2 голосов
/ 14 апреля 2011

Почти верно - рассмотрите это дерево наследования:

      Foo
     /   \
   Bar   Box

Если вы сейчас сделаете указатель так:

Bar* barry = new Box();

Вы получите хорошую ошибку компилятора , поскольку Box не может быть преобразовано в Bar. :)
Так что это только Foo<->Bar и Foo<->Box, а не Bar<->Box. Затем, когда boxxy является указателем Box, он будет вызывать функцию Box::F только в том случае, если он указан.
И, наконец, чтобы заставить подклассы реализовать определенную функцию, вы объявляете ее pure virtual, например:

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

Теперь подклассы (в данном случае Bar и Box), должны реализовать Func, иначе они не смогут скомпилироваться.

1 голос
/ 14 апреля 2011

Если вы объявите 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 ().

1 голос
/ 14 апреля 2011

А что изменится, если boxxy будет указателем Box?

Это позволит получить доступ к методам Box, не унаследованным от Foo.Указатель блока не может указывать на объекты Bar, поскольку Bar не является производным от Box.

И что произойдет, если производный класс не имеет переопределения для F ()?

Он унаследует реализацию F () от базового класса.

Наконец, чтобы избежать реализации функции для базового класса, но при этом разрешить полиморфизм, вы просто пишете пустойФункция body и объявить его виртуальным?

Это будет работать, но это не правильный способ сделать полиморфизм.Если вы не можете придумать конкретную реализацию для виртуальной функции базового класса, чтобы сделать эту функцию чисто виртуальной, не реализуйте ее как пустую функцию.

1 голос
/ 14 апреля 2011

Да, правильная функция F () будет вызываться в зависимости от типа объекта, который вы создали с помощью указателя Foo.

Если бы boxxy был указателем Box, вы могли бы вызвать только его F () или один из F () его производного класса, если только вы не сделали dynamic_cast для его родительского класса, а затем вызвали F ().

Чтобы избежать необходимости реализации в базовом классе, вы определяете его как pure virtual примерно так:

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

};
0 голосов
/ 14 апреля 2011
  • Я правильно понимаю?Да, если функция была объявлена ​​как виртуальная функция.
  • А что изменится, если boxxy будет указателем Box?Зависит от того, является ли функция виртуальной или нет.Виртуальная функция всегда будет вызывать правильную производную функцию;не виртуальная функция будет вызывать версию, основанную на типе указателя.
  • А что произойдет, если производный класс не имеет переопределения для F ()?Он будет использовать определение базового класса.
  • Наконец, чтобы избежать реализации функции для базового класса, но при этом разрешить полиморфизм, вы просто пишете пустое тело функции и объявляете его виртуальным?Вы также можете объявить его чисто виртуальным: virtual void F() = 0.Любой класс, который намеревается создать экземпляр в объекте, значительно переопределяет эту функцию и дает ей правильную реализацию.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...