Простейший способ объяснить это, вероятно, так:
Виртуальный поиск для вас, добавив виртуальную таблицу поиска.
Другими словами, еслиу вас не было виртуального ключевого слова, и вы переопределили метод, вам все равно пришлось бы вызывать этот метод вручную [простите, если моя память для синтаксиса C ++ немного ржавая]:
class A { void doSomething() { cout << "1"; } }
class B: public A { void doSomething() { cout << "2"; } }
class C: public A { void doSomething() { cout << "3"; } }
void someOtherFunc(A* thing) {
if (typeid(thing) == typeid(B)) {
static_cast<B*>(thing)->doSomething();
} else if (typeid(thing) == typeid(C)) {
static_cast<C*>(thing)->doSomething();
} else {
// not a derived class -- just call A's method
thing->doSomething();
}
}
ВыМожно немного оптимизировать это (для удобства чтения и производительности, скорее всего), используя таблицу поиска:
typedef doSomethingWithAnA(A::*doSomethingPtr)();
map<type_info, doSomethingWithAnA> A_doSomethingVTable;
void someOtherFuncA* thing) {
doSomethingWithAnA methodToCall = A_doSomethingVTable[typeid(thing)];
thing->(*methodToCall)();
}
Теперь это скорее высокоуровневый подход.Компилятор C ++, очевидно, может оптимизировать это немного больше, точно зная, что такое «type_info» и так далее.Так что, вероятно, вместо этой «карты» и поиска «methodToCall = aDoSomethingVTable [typeid (thing)]», затем вызов », компилятор вставляет что-то намного меньше и быстрее, например« doSomethingWithAnA * A_doSomethingVTable; », за которым следует« A_doSomethingTablething »-> type_number ".
Итак, вы правы, что C ++ на самом деле НЕ НУЖДАЕТСЯ в виртуальном, но он добавляет много синтаксического сахара, чтобы облегчить вашу жизнь, и может оптимизировать его тоже.
Тем не менее, я все еще думаю, что C ++ является ужасно устаревшим языком, с большим количеством ненужных сложностей. Например, виртуальный может (и, вероятно, должен ) быть принятым по умолчанию и оптимизироваться там, где это не нужно.Похожее на Scala ключевое слово "override" было бы гораздо полезнее, чем "virtual".