Czy pierwsze wywołanie ma taki sam koszt jak gdyby metoda nie była virtualna?
Czy drugie wywołanie ma taki sam koszt jak gdyby metoda nie była virtualna?
(niezadane pytanie)
To zależy od kompilatora. Przykładowo, co robi z tym cygwinowy g++ (akurat mam pod ręką) (skrócone):
Kopiuj
.text:004017BE mov [esp+10h+var_8], 1
.text:004017C6 mov [esp+10h+var_C], offset aB
.text:004017CE mov [esp+10h+var_10], offset std::cout
.text:004017D5 call std::__ostream_insert<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char const*,int)
.text:004017DA mov [esp+10h+var_10], 4
.text:004017E1 call __wrap__Znwj
.text:004017E6 mov dword ptr [eax], offset off_4030A0
.text:004017EC mov [esp+10h+var_10], eax
.text:004017EF call sub_401760
.text:004017F4 xor eax, eax
.text:004017F6 leave
.text:004017F7 retn
...
.text:00401760 sub_401760 proc near
.text:00401760 sub esp, 1Ch
.text:00401763 mov [esp+1Ch+var_14], 1
.text:0040176B mov [esp+1Ch+var_18], offset aB
.text:00401773 mov [esp+1Ch+var_1C], offset std::cout
.text:0040177A call std::__ostream_insert<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char const*,int)
.text:0040177F add esp, 1Ch
.text:00401782 retn
.text:00401782 sub_401760 endp
Czyli pierwsze wywołanie zostało zinlinowane (ok), a drugie nie zostało zinlinowane, ale również nie jest wirtualne (czyli półśrodek). Tak czy inaczej, nie płacisz za wywołane wirtualne w tym przypadku, bo kompilator może się domyślić jaki typ ma obiekt w tym momencie.
(chciałem sprawdzić jak się zachowa clang, ale na windowsie coś nie chce chodzić ładnie).
W ogólności w drugim przypadku wszystko będzie zależało od tego jak inteligentnie się zachowa kompilator.
- Czy da się za drugim wywołaniem ominąć runtime poliformizm?
Poza liczeniem na kompilator? Niezbyt.
Zależnie do czego tego potrzebujesz (i czy naprawdę warto), możesz spróbować zastosować CRTP (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).