Nel tuo esempio, la profondità dell'albero di ereditarietà non influisce sulle prestazioni. La ragione è semplice, ogni istanza ha il suo puntatore a qualche  vtable  (contenente i puntatori di funzione), e una chiamata di funzione virtuale va solo attraverso quel vtable. 
 In altre parole, il tuo codice funziona come il seguente codice C: 
struct vtable {
   void (*fooptr) (struct D1*);
};
struct D1 {
   const struct vtable*vptr;
};
struct D2 {
   const struct vtable*vptr;
};
 E ad es.    baseptr->foo()    è "trasformato" al tempo di compilazione a   baseptr->vptr.fooptr(baseptr)    (e ovviamente   d1ptr->foo()    è "trasformato" in   d1ptr->vptr.fooptr(d1ptr)    ecc ...) 
 Quindi il costo di esecuzione è lo stesso: prendi il vtable e chiama  indirettamente  il puntatore alla funzione all'interno. Il costo rimane lo stesso anche se disponi di una sottoclasse   struct D4    di   struct D3    sottoclasse di   struct D2    sottoclasse di   struct D1   . Potresti avere un   struct D99    con 99 ereditari e il costo di esecuzione sarebbe rimasto lo stesso. 
  Su alcuni processori, qualsiasi  chiamata indiretta  potrebbe essere più lenta di una chiamata  diretta , ad es. a causa del  predittore di ramo  costo  
 I dati del vtable sono costruiti al momento della compilazione (come dati statici costanti). 
 Le cose diventano un po 'più complesse con  ereditarietà virtuale  e / o  ereditarietà multipla  
 BTW, alcuni framework di oggetti C (ad es.  GObject  di Gtk, o diverse strutture di dati nel kernel di Linux) fornire i loro dati vtable (o di classe). Puntare a una struttura dati contenente puntatori di funzione è abbastanza comune (anche in C). Leggi anche le  chiusure  e vedrai una relazione con "vtables" (sia le chiusure che gli oggetti si mescolano codice con dati). 
 Alcuni compilatori C ++ (ad esempio  GCC ) possono fornire  devirtualization  come tecnica di ottimizzazione.