Java
Riguardo a Java, la tua premessa è completamente errata: non devi mai specificare che una funzione è virtuale - tutte le funzioni sono virtuali di default. Java fornisce final
per specificare che un metodo non può essere sovrascritto, il che ha un effetto un po 'simile, ma non è esattamente identico. Nella misura in cui final
significa "non virtuale", è ancora fatto nella direzione opposta: fondamentalmente e "opt-out" piuttosto che "opt-in".
C ++
Una delle cose che Bjarne ha sempre sottolineato su come progettare oggetti è stabilire e mantenere invarianti. Alcuni di questi invarianti hanno a che fare con valori, come "questo valore deve essere compreso tra 1 e 100" o "questo valore deve essere compreso tra 2 e 3 volte quel valore", ecc.
È ugualmente importante, tuttavia, stabilire e mantenere invarianti rispetto al comportamento di un oggetto. Questi invarianti stabiliscono una struttura all'interno della quale parti specifiche possono variare. A parte una programmazione davvero brutta, consente al programmatore di specificare e applicare determinati comportamenti tramite il meccanismo di controllo del tipo del compilatore.
Ad esempio, consideriamo un vettore C ++. Lo standard C ++ garantisce che un vettore C ++ fornisce una crescita costante ammortizzata. Se permettessimo di sovrascrivere la funzione di crescita di un vettore, una classe derivata da vector
potrebbe violare quel vincolo, ma dal momento che è (ipoteticamente) derivata pubblicamente da vector
, può essere utilizzata in qualsiasi posizione necessaria per un vettore, incluso il codice ciò può dipendere dal fatto che il vincolo viene applicato.
Rendere le funzioni virtuali è anche orientato all'utilizzo dell'ereditarietà. Bjarne ha (sempre così gentilmente) sottolineato per anni che molti programmatori sfruttano l'ereditarietà. È perfettamente adatto per progettare classi che non richiedono o utilizzare funzioni virtuali in tutti 1 .
Quindi no, questa decisione in C ++ non è interamente (o anche principalmente) per evitare l'overhead di chiamare una funzione virtuale. Principalmente si tratta di design di base e oggetti che rafforzano gli invarianti. Molti di questi invarianti si trovano sui dati di un oggetto, ma alcuni sono anche sul comportamento di un oggetto. Data l'importanza dell'impostazione degli invarianti, le funzioni dovrebbero essere non virtuali per impostazione predefinita, quindi gli invarianti vengono applicati per impostazione predefinita e il comportamento è aperto alle modifiche solo dove previsto.
1. Ad esempio, considera la sua intervista 2003 con Bill Venners .