2013-06-28 4 views
3

Я знаю, что ключевое слово virtual делает базовый класс полиморфным, и если я создаю объект и вызываю virtual function, соответствующая функция будет вызываться на основе распределения времени выполнения, но зачем мне создавать объект с разными типами. Я имею в видуИспользование создания базового класса полиморфным?

Base *ptr = new Derived; 

ptr->virtualfunction(); //calls the function which has implemented in Derived class. 

Если я создаю объект так, чтобы

Derived *ptr = new Derived; 
ptr->virtualfunction(); // which does the same without the need of making the function virtual. 
+3

проверьте пример здесь: http://www.cplusplus.com/doc/tutorial/polymorphism/, если вам нужна коллекция этих объектов или вы не знаете точный подтип объекта (потому что он зависит от конфигурация, ввод пользователя и т. д.), вам нужен полиморфизм. –

+0

Итак, ваш вопрос в том, почему существует необходимость в виртуальных методах? – Inspired

+1

_ "но зачем мне создавать объект с разными типами? _ Оба примера создают объект того же типа, разница - тип указателя, который вы используете для его ссылки, но оба примера создают' Derived'. –

ответ

8

Потому что вы можете хранить объекты различных типов вместе:

std::vector<std::unique_ptr<Base>> v; 

v.push_back(make_unique(new DerivedA())); 
v.push_back(make_unique(new DerivedB())); 
v.push_back(make_unique(new DerivedC())); 

Теперь, если вы идете на что vector:

for (auto& p : v) { 
    p->foo(); 
} 

Он будет называть foo() из DerivedA, B и C соответствующим образом.

+2

Вы должны добавить, что 'std :: make_unique' будет доступен начиная с C++ 14. Кроме того, по-настоящему безопасный способ его вызова будет: std :: make_unique () ', а не' std :: make_unique (new Foo()) '. Читайте здесь почему: http://www.gotw.ca/gotw/056.htm –

+0

и просто добавьте к этому - полиморфизм идет по цене, и эта цена представляет собой таблицу виртуальных методов (или vtable) для хранения указателей метода , Использование ключевого слова virtual - это способ сообщить компилятору «Я хочу полиморфизм, и я принимаю то, что это будет стоить» –

+0

@PaulManta Именно поэтому я не префикс его 'std'. 'make_unique', по крайней мере, под нынешним стандартом, является своего рода идиоматическим способом его написания, и я использовал его только для того, чтобы сократить пример. В любом случае, ваши взгляды на C++ 14 хороши. –

2

Давайте на простом примере: Допустим, у вас есть

class Base {}; 
class Derived1 : public Base {}; 
class Derived2 : public Base {}; 

Теперь, скажем, вы хотите, чтобы иметь возможность хранить в векторе (или контейнер) оба Derived1 и Derived2 экземпляров. В этом случае вы должны использовать базовый класс.

std::vector<Base*> 
// or std::vector<std::unique_ptr<Base>> 
1

Необходимость полиморфизма заключается в необходимости обработки разных данных таким же образом. Вместо того, чтобы переопределять один и тот же алгоритм для набора данных с разными формами, было бы намного проще иметь только одну реализацию этого алгоритма и параметризовать его с помощью разных операторов?

В этом суть полиморфизма. Вы начинаете с алгоритма, устанавливаете интерфейс, с которым он должен взаимодействовать, а затем создавайте реализации этого интерфейса. В C++ понятие интерфейса подразумевается в каждом классе. Любой класс предоставляет один интерфейс (хотя он может поддерживать многие интерфейсы через своих предков), а его потомки также реализуют его. Делая определенные методы виртуальными, потомки могут переопределять и адаптировать их к своим собственным внутренним структурам, не изменяя, как объект манипулируется снаружи.

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

Есть много полезных применений полиморфизма, но все они вытекают из приведенного выше принципа:

  • гетерогенного набора данных (как показано другими ответами),
  • injection (в котором различные реализации одного и того же интерфейса могут быть заменены друг на друга во время выполнения),
  • тестирование (а точнее, насмешка, в которой классы, которые взаимодействуют с данным классом C, заменяются манекенами, которые помогают проверить правильное поведение C),

, чтобы назвать несколько. Обратите внимание, что полиморфизм времени компиляции (шаблоны) и полиморфизм времени выполнения (virtual методы и наследование) достигают этой цели, хотя и по-другому, и с разными плюсами и минусами.