¿Cuál es el costo de llamar a una función virtual de una manera no polimórfica?

Tengo una base abstracta pura y dos clases derivadas:

struct B { virtual void foo() = 0; };
struct D1 : B { void foo() override { cout << "D1::foo()" << endl; } };
struct D2 : B { void foo() override { cout << "D1::foo()" << endl; } };

Hace llamarfoo en el punto A, ¿cuesta lo mismo que una llamada a una función miembro no virtual? ¿O es más caro que si D1 y D2 no hubieran derivado de B?

int main() {
 D1 d1; D2 d2; 
 std::vector<B*> v = { &d1, &d2 };

 d1.foo(); d2.foo(); // Point A (polymorphism not necessary)
 for(auto&& i : v) i->foo(); // Polymorphism necessary.

 return 0;
}

Responder: la respuesta deAndy Prowl es el tipo de respuesta correcta, solo quería agregar la salida del ensamblaje de gcc (probado enGodbolt: gcc-4.7 -O2 -march = nativo -std = c ++ 11). El costo de las llamadas a funciones directas es:

mov rdi, rsp
call    D1::foo()
mov rdi, rbp
call    D2::foo()

Y para las llamadas polimórficas:

mov rdi, QWORD PTR [rbx]
mov rax, QWORD PTR [rdi]
call    [QWORD PTR [rax]]
mov rdi, QWORD PTR [rbx+8]
mov rax, QWORD PTR [rdi]
call    [QWORD PTR [rax]]

Sin embargo, si los objetos no se derivan deB y usted acaba de realizar la llamada directa, gcc lo haráen línea la función llama:

mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:std::cout
call    std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)

Estapodría habilitar más optimizaciones siD1 yD2 no derivar deB así que supongo queno, no son equivalentes (Al menos para esta versión de gcc con estas optimizaciones, -O3 produjo una salida similar sin alinear). ¿Hay algo que impida que el compilador se incorpore en el caso de queD1 yD2 derivar deB?

"Fijar": use delegados (también puede reimplementar funciones virtuales):

struct DG { // Delegate
 std::function<void(void)> foo;
 template<class C> DG(C&& c) { foo = [&](void){c.foo();}; }
};

y luego crear un vector de delegados:

std::vector<DG> v = { d1, d2 };

esto permite la inclusión si accede a los métodos de forma no polimórfica. Sin embargo, supongo que acceder al vector será más lento (o al menos tan rápido porquestd::function usa funciones virtuales para el borrado de tipos) que simplemente usar funciones virtuales (aún no se puede probar con godbolt).

Respuestas a la pregunta(2)

Su respuesta a la pregunta