2010-06-16 15 views
18

Zostałem poproszony o to szalone pytanie. Nie mogłem się doczekać.Wywiad pytanie o funkcje wirtualne w C++

Czy metoda w klasie bazowej, która jest zadeklarowana jako wirtualna, może zostać wywołana przy użyciu wskaźnika klasy bazowej, który wskazuje na obiekt klasy pochodnej?

Czy to możliwe?

+9

Może chcesz otrzymać jedna z książek wprowadzających z [The Definitive C++ Book Guide and List] (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). –

+2

@ James: Myślę, że pyta, czy możesz wywołać 'base :: foo()' not' derived :: foo() 'używając' p' jeśli 'p' jest' base * 'i wskazuje' na ' ' –

+0

@John: A więc? Jednak James ma rację. – sbi

Odpowiedz

49

Jeśli próbujesz wywołać metodę wirtualną za pomocą wskaźnika klasy bazowej, tak.

To polimorfizm.

Jeśli pytasz, z wskaźnikiem klasy bazowej do klasy pochodnej, czy możesz wywołać metodę klasy bazowej, która jest nadpisywana przez klasę pochodną? Tak to jest również możliwe poprzez wyraźne określenie zakresu nazwę klasy bazowej:

basePtr->BaseClass::myMethod();

+4

Polimorfizm to miejsce, w którym klasyfikuje metodę klasy pochodnej, ponieważ metoda jest wirtualna w klasie bazowej. Faktycznie wywołanie metody klasy bazowej za pomocą wskaźnika do podstawy, nawet jeśli metoda klasy bazowej została nadpisana, omija polimorfizm, który jest inny. –

+1

W rzeczywistości jest odwrotnie. Pytanie polega na wywołaniu wirtualnej metody klasy podstawowej, gdy obiekt jest typu pochodnego, który zastępuje metodę. – JaredPar

+5

Hrm, pytanie w formie pisemnej było mylące. – Alan

10

Masz na myśli coś takiego. (Gdzie pBase jest typu wskaźnik do bazy ale wskazywanego obiektu jest rzeczywiście typu Derived który pochodzi z Base.)

pBase->Base::method(); 

Tak, jest to możliwe.

16

Spróbuj:

class A   { virtual void foo(); } 
class B : public A { virtual void foo(); } 

A *b = new B(); 
b->A::foo(); 
+4

Właściwie uważam, że powinno to być "A * b = nowe B()", zamiast "B * b = nowe B()", aby podążać za pytaniem. – Luca

+1

Tak, powinno. –

-1

Nie, nie w czystym sposób. Ale tak. Musisz wykonać manipulację wskaźnikiem, uzyskać wskaźnik do tabeli vtable i nawiązać połączenie. ale to nie jest dokładnie wskaźnik do klasy bazowej, ale pewne manipulacje inteligentnymi wskaźnikami. Inne podejście polega na użyciu operatora rozróżniania zakresów w klasie bazowej.

+0

C++ obsługuje bezpośrednio to, o co pyta. 'base-> base :: function()' zrobiłoby lewę. Nie trzeba tu podłączać hakerów. –

+2

Ponownie przeczytaj swój wpis. "operator zakresu rozdzielczości" nie jest "innym podejściem". Jest to jedyne podejście, które należy wziąć pod uwagę. –

+0

Zgadzam się. Zakres Rozdzielczość jest drogą .. –

10

Tak - trzeba podać pełną nazwę choć:

#include <iostream> 

struct base { 
    virtual void print() { std::cout << "Base"; } 
}; 

struct derived : base { 
    virtual void print() { std::cout << "Derived"; } 
}; 

int main() { 
    base *b = new derived; 
    b->base::print(); 
    delete b; 
    return 0; 
} 
5

Jeśli dobrze rozumiem pytanie, masz

class B 
{ 
public: 
    virtual void foo(); 
}; 

class D: public B 
{ 
public: 
    virtual void foo(); 
} 

B* b = new D; 

I pytanie jest, można zadzwonić B::foo().Odpowiedź brzmi: tak, używając

b->B::foo() 
0
class B 
{ 
public: 
    virtual void foo(); 
}; 

class D: public B 
{ 
public: 
    virtual void foo(); 
} 

B* b = new D; 

Spróbuj zadzwonić

(*b).foo() 

aby wywołać funkcję klasa bazowa Foo

+0

jesteś pewien, że to wywoła funkcję klasy podstawowej foo? testowałeś to? – Vijay

+0

To było moje ogólne założenie, że (* b) w końcu będzie mieć odpowiedni obiekt, ale podczas kompilacji i uruchamiania stwierdziłem, że tak nie jest. Nadal wywołuje funkcję pochodną. Stworzyło zamieszanie dla mnie również to, co jest różnica między (* b) .foo() i B B1 = * b; b1.foo() – Pardeep

0
class B { 
    public: virtual void foo(); 
}; 

class D: public B { 
    public: virtual void foo() 
    { 
     B::foo(); 
    }; 
} 

B* b = new D; 

rozwiązania:

  1. b->foo();
  2. b->B::foo()

  3. lub nie zastępują/zdefiniować foo() w klasie D oraz pochodzącego zadzwonić b-> foo()

  4. B objb = *b; objb.foo() ; // this is object slicing and not (*b).foo() as in one of the previous answers