Es importante darse cuenta de que el upcasting sólo maneja direcciones. Si el compilador tiene un objeto, sabe su tipo concreto y por tanto (en C++) no usará la ligadura dinámica para ninguna de las llamadas a funciones - o como mínimo el compilador no necesitará usar la ligadura dinámica. Por cuestiones de eficiencia, la mayoría de los compiladores usarán la ligadura estática cuando estén haciendo una llamada a una función virtual de un objeto porque saben su tipo concreto. Aquí hay un ejemplo:
//: C15:Early.cpp // Early binding & virtual functions #include <iostream> #include <string> using namespace std; class Pet { public: virtual string speak() const { return ""; } }; class Dog : public Pet { public: string speak() const { return "Bark!"; } }; int main() { Dog ralph; Pet* p1 = &ralph; Pet& p2 = ralph; Pet p3; // Late binding for both: cout << "p1->speak() = " << p1->speak() <<endl; cout << "p2.speak() = " << p2.speak() << endl; // Early binding (probably): cout << "p3.speak() = " << p3.speak() << endl; } ///:~
Listado 15.5. C15/Early.cpp
En p1->speak() y en p2.speak(), se usan direcciones, lo que significa que la información es incompleta: p1 y p2 pueden representar la dirección de una Pet o algo que derive de una Pet, por lo que debe usarse el mecanismo virtual. Cuando se llama a p3.speak no existe ambigüedad. El compilador conoce el tipo exacto y sabe que es un objeto, por lo que es imposible que sea un objeto derivado de Pet - es exactamente una Pet. Por esto, probablemente se use la ligadura estática. Sin embargo, si el compilador no quiere trabajar tanto, puede seguir usando la ligadura dinámica y el comportamiento será el mismo.