2014-09-23 17 views
6

header.hRozdzielczość funkcji wirtualnego z domyślnymi parametrami

#include <iostream> 
using namespace std; 
class A 
{ 
    public: 
     virtual void display(int i=5) { cout<< "Base::" << i << endl; } 
}; 

class B : public A 
{ 
    public: 
     void display(int i=9) { cout<< "Derived::" << i << endl; } 
}; 

source.h

#include <iostream> 
#include "header.h" 
using namespace std; 
int main() 
{ 
    A * a = new B(); 
    a->display(); 

    A* aa = new A(); 
    aa->display(); 

    B* bb = new B(); 
    bb->display(); 
} 

wyjście

Derived::5 
Base::5 
Derived::9 

Moje zrozumienie to domyślne funkcje parametrów zostały rozwiązane podczas kompilacji przy użyciu przeciążenia funkcji. Wirtualne funkcje zostały następnie rozwiązane w czasie wykonywania za pomocą nadpisywania funkcji.

Ale to, co się dzieje, to bałagan.
Jak działa tutaj funkcja rozwiązywania problemów?

+1

'Domyślna rozdzielczość argument opiera się na statycznym typu obiektu, przez którą nazywamy zakresie funkcji (tj na podstawie typu wskaźnika). http://social.msdn.microsoft.com/Forums/pl-PL/90b9b8ee-ed5f-4ba8-93b5-612c4d906124/default-argument-and-inheritance-hierarchy –

+0

Pamiętaj, że możesz obejść ten problem przez przeciążenie wirtualnego funkcja z inną wirtualną funkcją bez parametru, która "przesyła dalej" do tej z parametrem.Podobnie jak: w Base 'virtual void display() {display (9); } 'and in Derived' void display() {display (5); } ' – leemes

Odpowiedz

7

kod jest faktycznie postrzegana przez kompilator tak:
(Metoda display() nie jest rzeczywiście istnieje, ale rozwiązywanie działa w podobny sposób)

class A 
{ 
public: 
    virtual void display(int i) { cout<< "Base::" << i << endl; } 
    void display() { display(5); } 
}; 

class B : public A 
{ 
public: 
    void display(int i) override { cout<< "Derived::" << i << endl; } 
    void display() { display(9); } 
}; 

Teraz należy zrozumieć, co się dzieje. Jesteś dzwoniąc pod numer nie-wirtualny display(), który wywołuje funkcję wirtualną. W bardziej ostrych słowach: domyślny argument jest rozwiązywany tak, jakby była tam nie-wirtualna metoda - według typu zmiennej (a nie według rzeczywistego typu obiektu), ale kod zostanie wykonany zgodnie z do rzeczywistych obiektów typu, ponieważ jest to metoda wirtualna:

int main() 
{ 
    A * a = new B(); // type of a is A* real type is B 
    a->display(); // calls A::display() which calls B::display(5) 

    A* aa = new A(); // type of aa is A* real type is A 
    aa->display(); // calls A::display() which calls A::display(5) 

    B* bb = new B(); // type of bb is B* real type is B 
    bb->display(); // calls B::display() which calls B::display(9) 
} 
+0

O, właśnie tego szukałem.Hej, ale jak drukowane jest 'Derived :: 5'? Powinno to być 'Base :: 5' – cppcoder

+0

Gdy wywołujesz' a-> display(); 'na obiekcie typu (dynamicznego)' B', wywołuje 'display();', to jest ** non- wirtualne przeciążenie ** 'display()', które wywołuje 'display (5);' który jest ** praktycznie ** rozwiązany na 'B :: display (5)'. W oryginalnym kodzie dzieje się coś podobnego. Zamiast dodatkowej funkcji innej niż wirtualna jest to parametr domyślny, który jest rozwiązywany w ** typie statycznym **. – leemes

+1

Hmm, to jest skomplikowane. – cppcoder

7

Nie ma polimorfizmu na domyślnych argumentach. Są rozwiązywane podczas kompilacji.

A::display ma domyślną argumentu równego 5. B::display ma domyślną argumentu równego 9. To tylko rodzaj a, aa, bb zmiennych liczy.

Użycie różnych domyślnych argumentów w metodach polimorficznych jest mylące i powinno się ich unikać.

+0

Przykro mi, ale nie rozumiem: dlaczego' a-> display() 'pokazuje' Derived :: 5' i 'bb-> display()' pokazuje 'Derived :: 9'? Są one zdefiniowane w dokładnie taki sam sposób ... –

+2

@StefanoF Ponieważ 'a' jest typu' A * ', podczas gdy' bb' jest typu 'B *'. Stąd 'a-> display()' używa deklaracji z 'klasy A' podczas gdy' bb-> ​​display() 'używa tego z' klasy B'' –

5

zachowanie to jest określone w rozdział 8.3.6: domyślne argumenty ciągu Programming languages — C++ (ISO/IEC 14882:2003(E)):

wywołanie funkcji wirtualnej (10.3) używa domyślny argume NTS w deklaracji funkcji wirtualnego ustalonej przez statyczny typu wskaźnika lub odniesienia oznaczające przedmiot