Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Oddzielanie klas dziedziczących wirtualnie.

Ostatnio zmodyfikowano 2015-07-28 19:56
Autor Wiadomość
Kaikso
Temat założony przez niniejszego użytkownika
Oddzielanie klas dziedziczących wirtualnie.
» 2015-07-25 01:30:55
C/C++
// Klasy bazowe od których zaczyna się cała historia
class Bazowa_A;
class Bazowa_B;
class Bazowa_C;

// Klasy pochodne - I Pokolenie
class Pochodna_AB
    : virtual public Bazowa_A
     , virtual public Bazowa_B;

class Pochodna_AC
: virtual public Bazowa_A
     , virtual public Bazowa_C;

class Pochodna_BC
: virtual public Bazowa_B
     , virtual public Bazowa_C;

// Klasy pochodne - II Pokolenie
class Pochodna_AB_BC // Klasa Bazowa_B jest wspólna dla obu klas bazowych
: virtual public Pochodna_AB
     , virtual public Pochodna_AC;

// Nasza klasa
class Klasa_X final
: public Pochodna_BC
     , public Pochodna_AB_BC;

Uwaga! Wszystkie klasy bazowe pochodzą z zewnętrznej biblioteki, na którą ja nie mam wpływu.

A więc potrzebuję stworzyć klasę, która dziedziczy niewirtualnie po dwóch klasach. Niestety te klasy przez owe dziedziczenie wirtualne wchodzą w konflikt. Jeśli ktoś zna jakąś sztuczkę na oddzielenie składowych klas bazowych od siebie nawzajem, to proszę o sugestię.

@Edit: Tak chyba czytelniej.
P-135184
notabigthreat
» 2015-07-25 01:43:24
A dlaczego potrzebujesz dziedziczyć niewirtualnie?
P-135185
Kaikso
Temat założony przez niniejszego użytkownika
» 2015-07-25 01:49:14
@Up: Wyżej jest wytłumaczone. Klasy bazowe wchodzą nawzajem w konflikt, z powodu wspólnych klas bazowych najwyższego poziomu.
P-135186
Monika90
» 2015-07-25 10:24:07
Klasa_X w ogóle nie zależy od klasy Pochodna_BC. Po co więc pokazujesz nam Pochodna_BC?
P-135188
Kaikso
Temat założony przez niniejszego użytkownika
» 2015-07-25 12:33:57
Mój błąd, schemat kodu miał wyglądać nieco inaczej. Ale to niczego nie zmienia i wciąż oddaje istotę problemu.

@Edit: Poprawiłem kod.
P-135197
Monika90
» 2015-07-25 13:57:38
Nie wiem o jakim problemie mówisz. W twoim kodzie każda klasa podstawowa klasy Klasa_X ma jednoznaczną ścieżkę dostępu.

C/C++
class Bazowa_A { };
class Bazowa_B { };
class Bazowa_C { };

// Klasy pochodne - I Pokolenie
class Pochodna_AB
    : virtual public Bazowa_A
     , virtual public Bazowa_B
{ };

class Pochodna_AC
    : virtual public Bazowa_A
     , virtual public Bazowa_C
{ };

class Pochodna_BC
    : virtual public Bazowa_B
     , virtual public Bazowa_C
{ };

// Klasy pochodne - II Pokolenie
class Pochodna_AB_BC // Klasa Bazowa_B jest wspólna dla obu klas bazowych
    : virtual public Pochodna_AB
     , virtual public Pochodna_AC
{ };

// Nasza klasa
class Klasa_X final
    : public Pochodna_BC
     , public Pochodna_AB_BC
{ };

int main()
{
    Klasa_X x;
    Bazowa_A * p1 = & x;
    Bazowa_B * p2 = & x;
    Bazowa_C * p3 = & x;
    Pochodna_AB * p4 = & x;
    Pochodna_AC * p5 = & x;
    Pochodna_BC * p6 = & x;
    Pochodna_AB_BC * p7 = & x;
}
Kompilator też nie widzi problemu.
P-135204
Kaikso
Temat założony przez niniejszego użytkownika
» 2015-07-25 14:45:06
Tu chodzi o błąd w czasie wykonania.

C/C++
#include <iostream>

struct Bazowa_A { int a; };
struct Bazowa_B { int b; };
struct Bazowa_C { int c; };

// Klasy pochodne - I Pokolenie
class Pochodna_AB
    : virtual public Bazowa_A
     , virtual public Bazowa_B
{ };

class Pochodna_AC
    : virtual public Bazowa_A
     , virtual public Bazowa_C
{ };

class Pochodna_BC
    : virtual public Bazowa_B
     , virtual public Bazowa_C
{
public:
    Pochodna_BC( int b, int c )
    {
        this->b = b;
        this->c = c;
    }
   
    virtual void test_bc()
    {
        std::cout << "----- test_bc() ------" << std::endl;
        std::cout << "b = " << b << std::endl;
        std::cout << "c = " << c << std::endl;
    }
};

// Klasy pochodne - II Pokolenie
class Pochodna_AB_BC // Klasa Bazowa_B jest wspólna dla obu klas bazowych
    : virtual public Pochodna_AB
     , virtual public Pochodna_AC
{
public:
    Pochodna_AB_BC( int a, int b, int c )
    {
        this->a = a;
        this->b = b;
        this->c = c;
    }
};

// Nasza klasa
class Klasa_X final
    : public Pochodna_BC
     , public Pochodna_AB_BC
{
public:
    Klasa_X()
        : Pochodna_BC( 0, 1 )
         , Pochodna_AB_BC( 2, 3, 4 )
    { }
};

int main()
{
    Klasa_X x;
    x.test_bc();
   
    return 0;
}

Oczekiwany wynik:
----- test_bc() ------
b = 0;
c = 1;

Prawdziwy wynik:
----- test_bc() ------
b = 3;
c = 4;

A teraz wyobraźcie sobie, że to są np. wskaźniki do świeżo zaalokowanych obiektów. Efekt gwarantowany crash aplikacji.
P-135206
jankowalski25
» 2015-07-25 15:17:00
[Wikipedia] ​Lista_inicjalizacyjna_konstruktora
Kolejność wywołań konstruktorów klasy bazowej czy też obiektów składowych jest ściśle określona (zobacz: konstruktor) i nie jest ważna kolejność w jakiej zostaną napisane wywołania konstruktorów klas bazowych na liście inicjalizacyjnej.
Konstruktory klas bazowych w kolejności w jakiej znajdują się w sekcji dziedziczenia w deklaracji klasy pochodnej.
P-135210
« 1 » 2 3
  Strona 1 z 3 Następna strona