Czym w C++ jest wirtualna klasa bazowa?

Chcę wiedzieć, czym jest" wirtualna klasa bazowa " i co ona oznacza.

Pozwól mi pokazać przykład:

class Foo
{
public:
    void DoSomething() { /* ... */ }
};

class Bar : public virtual Foo
{
public:
    void DoSpecific() { /* ... */ }
};
Author: manlio, 2008-08-22

10 answers

Virtual base classes, używane w dziedziczeniu wirtualnym, jest sposobem zapobiegania wielokrotnym "instancjom" danej klasy pojawiającym się w hierarchii dziedziczenia przy użyciu dziedziczenia wielokrotnego.

Rozważ następujący scenariusz:

class A { public: void Foo() {} };
class B : public A {};
class C : public A {};
class D : public B, public C {};

Powyższa hierarchia klas skutkuje "przerażającym diamentem", który wygląda tak:

  A
 / \
B   C
 \ /
  D

Instancja D będzie składać się z B, które zawiera A, I C, które również zawiera A. więc masz dwie "instancje" (dla potrzeby lepszego wyrażenie) A.

Kiedy masz taki scenariusz, masz możliwość dwuznaczności. Co się dzieje, gdy to robisz:

D d;
d.Foo(); // is this B's Foo() or C's Foo() ??

Wirtualne dziedziczenie jest po to, aby rozwiązać ten problem. Gdy określisz wirtualne dziedziczenie klas, powiesz kompilatorowi, że chcesz tylko jedną instancję.

class A { public: void Foo() {} };
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};

Oznacza to, że w hierarchii jest tylko jedna "instancja" A. Stąd

D d;
d.Foo(); // no longer ambiguous

Mam nadzieję, że to pomoże jako mini podsumowanie. Więcej informacji, przeczytaj to i to. Dobry przykład jest również dostępny tutaj .

 484
Author: OJ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-23 11:58:15

O układzie pamięci

Na marginesie, problem z przerażającym diamentem polega na tym, że klasa bazowa jest obecna wiele razy. Więc z regularnym dziedziczeniem wierzysz, że masz:

  A
 / \
B   C
 \ /
  D

Ale w układzie pamięci masz:

A   A
|   |
B   C
 \ /
  D

To wyjaśnia, dlaczego podczas wywołania D::foo(), masz problem z niejednoznacznością. Ale prawdziwy problem pojawia się, gdy chcesz użyć zmiennej członkowskiej A. Na przykład, powiedzmy, że mamy:

class A
{
    public :
       foo() ;
       int m_iValue ;
} ;

Kiedy spróbujesz dostęp m_iValue z D kompilator będzie protestował, ponieważ w hierarchii będzie widział dwa m_iValue, a nie jeden. A jeśli zmodyfikować jeden, powiedzmy, B::m_iValue (to jest A::m_iValue rodzic B), C::m_iValue nie będzie modyfikowany (to jest A::m_iValue rodzic C).

Tutaj przydaje się wirtualne dziedziczenie, ponieważ dzięki niemu powrócisz do prawdziwego układu diamentowego, z nie tylko jedną metodą foo(), ale także jedną i tylko jedną m_iValue.

Co może pójść źle?

Imagine:

  • A ma jakąś podstawową funkcję.
  • B dodaje do niego jakąś fajną tablicę danych (na przykład)
  • C dodaje do niego jakąś fajną funkcję, taką jak wzór obserwatora(na przykład na m_iValue).
  • D dziedziczy z B i C, a więc z A.

Przy dziedziczeniu normalnym modyfikowanie m_iValue z D jest niejednoznaczne i należy to rozwiązać. Nawet jeśli jest, w środku są dwa m_iValues, więc lepiej o tym pamiętać i aktualizować dwa w tym samym czasie.

Z wirtualnym dziedziczeniem, modyfikowanie m_iValue z D jest ok... Ale... Powiedzmy, że masz D. Poprzez interfejs C, podłączyłeś obserwatora. I poprzez interfejs B, aktualizujesz tablicę cool, która ma efekt uboczny bezpośredniej zmiany m_iValue...

Ponieważ zmiana m_iValue odbywa się bezpośrednio (bez użycia metody virtual accessor), obserwator "nasłuchuje" przez C nie będzie wywoływany, ponieważ kod implementujący nasłuchiwanie jest w C, a B o tym nie wie...

Podsumowanie

Jeśli masz diament w swojej hierarchii, oznacza to, że masz 95%, Aby zrobić coś złego z tą hierarchią.
 216
Author: paercebal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-11 01:03:29

Wyjaśnienie dziedziczenia wielokrotnego za pomocą wirtualnych baz wymaga znajomości modelu obiektowego C++. A Wyjaśnienie tematu najlepiej zrobić w artykule, a nie w polu komentarza.

Najlepszym, czytelnym wyjaśnieniem, które rozwiązało wszystkie moje wątpliwości na ten temat był ten artykuł: http://www.phpcompiler.org/articles/virtualinheritance.html

Naprawdę nie będziesz musiał czytać nic innego na ten temat (chyba że jesteś kompilatorem) po przeczytaniu to...

 29
Author: lenkite,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-14 18:14:56

Wirtualna klasa bazowa to klasa, która nie można utworzyć instancji : nie można utwórz z niego bezpośredni obiekt.

Myślę, że mylisz dwie bardzo różne rzeczy. Dziedziczenie wirtualne nie jest tym samym, co klasa abstrakcyjna. Dziedziczenie wirtualne modyfikuje zachowanie wywołań funkcji; czasami rozwiązuje wywołania funkcji, które w przeciwnym razie byłyby niejednoznaczne, czasami odkłada obsługę wywołań funkcji do klasy innej niż ta, której można by oczekiwać w nie-wirtualnej spadek.
 10
Author: wilhelmtell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 01:47:36

Chciałbym dodać do tego rodzaju wyjaśnień OJ.

Wirtualne dziedzictwo nie jest bez ceny. Podobnie jak w przypadku wszystkich wirtualnych rzeczy, dostajesz hit wydajności. Istnieje sposób obejścia tego hitu, który jest prawdopodobnie mniej elegancki.

Zamiast łamać diament poprzez wirtualne wyprowadzanie, możesz dodać kolejną warstwę do diamentu, aby uzyskać coś takiego:

   B
  / \
D11 D12
 |   |
D21 D22
 \   /
  DD

Żadna z klas nie dziedziczy praktycznie, wszystkie dziedziczą publicznie. Klasy D21 i D22 ukryją się wtedy funkcja wirtualna f (), która jest niejednoznaczna dla DD, być może przez zadeklarowanie funkcji prywatnej. Każda z nich definiuje funkcję wrappera, odpowiednio f1() i f2 (), każda wywołująca klasę-lokalną (prywatną) f (), rozwiązując w ten sposób konflikty. Klasa DD wywołuje f1 () jeśli chce D11::f () i f2 () jeśli chce D12:: f (). Jeśli zdefiniujesz owijarki w linii, prawdopodobnie otrzymasz około zero kosztów.

Oczywiście, jeśli możesz zmienić D11 i D12 to możesz zrobić ten sam trik wewnątrz tych klas, ale często jest to Nie w tej sprawie.

 6
Author: wilhelmtell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 08:13:15

Oprócz tego, co zostało już powiedziane o dziedziczeniu wielokrotnym i wirtualnym, istnieje bardzo interesujący artykuł w Dzienniku doktora Dobba: dziedziczenie wielokrotne uważane za przydatne

 4
Author: Luc Hermitte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 00:58:41

Jesteś trochę zagmatwany. Nie wiem, czy mieszasz jakieś pojęcia.

Nie masz wirtualnej klasy bazowej w swojej operacji.

Zrobiłeś wirtualny spadek. Jest to zwykle używane w dziedziczeniu wielokrotnym, tak że wiele klas pochodnych używa członków klasy bazowej bez powielania ich.

Klasa bazowa z czystą funkcją wirtualną nie jest tworzona. to wymaga składni, którą Paul dostaje. Jest zwykle używany tak klasy pochodne muszą definiować te funkcje.

Nie chcę już wyjaśniać, bo nie do końca rozumiem, o co prosisz.

 1
Author: Baltimark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 01:48:04

Oznacza to, że wywołanie funkcji wirtualnej zostanie przekazane do klasy "right".

C++ FAQ Lite FTW.

W skrócie, jest często używany w scenariuszach wielokrotnego dziedziczenia, gdzie powstaje" diamentowa " hierarchia. Dziedziczenie wirtualne złamie dwuznaczność utworzoną w dolnej klasie, gdy wywołasz funkcję w tej klasie i funkcja musi być rozwiązana do klasy D1 lub D2 powyżej tej dolnej klasy. Zobacz element FAQ dla diagramu i szczegóły.

Jest również używany w sister delegation , potężnej funkcji (choć nie dla osób o słabym sercu). Zobacz to FAQ.

Patrz także pozycja 40 w efektywnym C++ wydanie 3 (43 w wydaniu 2).

 1
Author: wilhelmtell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-23 11:58:23

Diamond inheritance runnable usage example

Ten przykład pokazuje, jak użyć wirtualnej klasy bazowej w typowym scenariuszu: do rozwiązania dziedziczenia diamentów.

#include <cassert>

class A {
    public:
        A(){}
        A(int i) : i(i) {}
        int i;
        virtual int f() = 0;
        virtual int g() = 0;
        virtual int h() = 0;
};

class B : public virtual A {
    public:
        B(int j) : j(j) {}
        int j;
        virtual int f() { return this->i + this->j; }
};

class C : public virtual A {
    public:
        C(int k) : k(k) {}
        int k;
        virtual int g() { return this->i + this->k; }
};

class D : public B, public C {
    public:
        D(int i, int j, int k) : A(i), B(j), C(k) {}
        virtual int h() { return this->i + this->j + this->k; }
};

int main() {
    D d = D(1, 2, 4);
    assert(d.f() == 3);
    assert(d.g() == 5);
    assert(d.h() == 7);
}
 1
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-20 12:59:25

Klasy wirtualne to nie to samo co dziedziczenie wirtualne. Wirtualne klasy, których nie można utworzyć, wirtualne dziedziczenie to coś zupełnie innego.

Wikipedia opisuje to lepiej niż ja. http://en.wikipedia.org/wiki/Virtual_inheritance

 0
Author: bradtgmurray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 01:52:04