Klasa finalna, po co taki zabieg ?

0

Oto mam nadzieje dobra implementacja klasy finalnej (nie da sie po niej dziedziczyc), mam kilka pytan w komentarzu w kodzie...

class Bazowa {
private:
	Bazowa() {}
	~Bazowa() {}
	friend class Pochodna;   // czemu sluzy ten zabieg
};

class Pochodna : virtual public Bazowa { };  //czemu sluzy ten zabieg (przeciez nie ma duplikacji danych)

class DrugaPochodna : public Bazowa { };

int main()
{
Pochodna Pobj;
//DrugaPochodna DPobj; // nie przejdzie
}

 

za gory dzieki za info

0

Gdzieś to już opisywałem, ale nie mam pod ręką ;]
Konstruktor klasy Bazowa jest prywatny (!) co oznacza że wywolać go może tylko ktoś zaprzyjaźniony. Po to też klasa Pochodna jest deklarowana jako friend, żeby mogła ten konstruktor wywołać (a musi, tworząc swój obiekt). Problem w tym ze konstruktory są wołane niejako po kolei. Tzn konstruktor klasy nizej woła ten wyższy itd. W takim razie cały ten zabieg z prywatnym konstruktorem psu na budę, bo i tak to Pochodna zawsze będzie wołać konstruktor Bazowej. Po to właśnie mamy dziedziczenie wirtualne. Proponuje poczytać o tym jak ono właściwie działa ;) W skrócie polega to na tym że obiekt klasy dziedziczonej wirtualnie jest tworzony na początku (!) konstruowania obiektu który z takiej klasy dziedziczy wirtualne. Czyli nie ma wężyka Pochodna3->Pochodna2->Pochodna1->Bazowa tylko Bazowa jest tworzona od razu na poziomie Pochodna3 (w ten sposób wykluczamy sytuację że ten sam kod pojawi się wiecej niz raz). Co nam to daje? Otóz jedyna (!) klasa która moze wywołać konstruktor Bazowej to Pochodna. Żadna inna. W szczególności nie moze tego zrobić klasa dziedzicząca z Pochodnej (bo "przyjaźni" się nie dziedziczy).

0

I coś mi się wydaje, że w tym kodzie to Bazowa powinna się nazywać... bo ja wiem, "Final"? I wtedy " : virtual public Final" robiłoby za słówko "final" z Javy.
Co znaczy, że Pochodna jest finalną, bo nie można już po niej dziedziczyć. Aby jakąś inną klasę też zrobić finalną, to trzeba by dodać przyjaźć w Final i... " : virtual public Final".
W tej chwili w kodzie wygląda to tak, jakby chodziło o Bazową.

0

I niech mi ktos wyjasni w jakim celu tutaj jest uzywane dziedziczenie wirtualne? Przeciez to tylko do wielodziedziczenia

Pozdrawiam serdecznie

0

class Final {
private:

    Final() { }
    ~Final() { }
    friend class MyFinalClass; 
    friend class MyAlmostFinalClass; 
};

class MyFinalClass : virtual public Final {
}; 

class MyAlmostFinalClass : public Final { // <<< brak virtual
};

class ImWorking : public MyAlmostFinalClass {
};

class ImWrong : public MyFinalClass {
};



int main() {
    MyFinalClass final;
    MyAlmostFinalClass almostFinal; 
    ImWorking working; // przejdzie
//    ImWrong wrong; // nie przejdzie
    return 0;
}

No i masz babo placek. ;)

edit:
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Final_Class

The idiom depends on the following C++ rule: the constructor (and destructor) of a virtually inherited class is called directly by the derived-most class. If access to the constructor or destructor of such a virtually inherited class is prevented, the class can not be subclassed further.

1

@LexUK wiem ze mój post był dość dlugi (jak na mnie :P) ale wyjaśniłem w nim po co dziedziczenie jest wirtualne. Wynika to nie z jego typowego zastosowania, a tego jak technicznie jest realizowane.

0
letni napisał(a)

class DrugaPochodna : public Bazowa { };



 na 95% powinno byc  : public Pochodna {}; 

daje nam to to , że z virtualnym dziedziczeniem wcześniej nie pójdzie, bez będzie ok . 

Bez virtual : 

druga pochodna woła Pochodną a ta Bazową    - > konstruktory   Bazowa -> Pochodna -> Druga  =wszystko ok

Z virtual :

Tworzenie  Bazowej i  Pochodnej "niezależnie"  - brak dostępu Drugiej pochodnej do konstruktora Bazowej.
0

@adf88 a jesteś pewny ze to co napisałeś zadziała tak samo? Chyba jednak nie ;)
Zauważ że zrobimy klasę dziedziczącą z PikenyprzykladKlasyPoKtorejNieMoznaDziedziczyc która jest z nią zaprzyjaźniona. Wszystko jest ok. A teraz zróbmy klasę dziedziczącą z tej dziedziczącej i co? Nadal działa. A nas interesowała taka sytuacja żeby jedna się nie dało i żeby dziedziczenie z klas tej hierarchii było niemożliwe.
Prywatny konstruktor to żadne rozwiązanie bo wymaga od nas pisania mechanizmu fabryki / dowolnego innego do tworzenia takich obiektów.

0

Jakaś masakra to rozwiązanie. Zrozumie to tylko ktoś tylko chyba siedzący w C++ od zawsze.
A nie lepiej zrobić pimpl? Wtedy środka też nie podziedziczysz.

class file
{
private:

    class impl;
    shared_ptr<impl> pimpl_;

public:
    file(char const * name, char const * mode);
    void read(void * data, size_t size);
};

albo jeszcze normalniej factory + wszędzie indziej interfejsy?

0

Przecież przy tym co pokazałeś nadal można dziedziczyć z file.

0

Tak się składa, że jestem autorem kodu źródłowego, który jest umieszczony w pierwszym poście (tj. w temacie).

Shalom napisał, że "W takim razie cały ten zabieg z prywatnym konstruktorem psu na budę, bo i tak to Pochodna zawsze będzie wołać konstruktor Bazowej. " i to się zgadza, ponieważ oryginalnie klasa bazowa wyglądała tak:

class Bazowa {
private:
~Bazowa() {}
friend class Pochodna;
};

Nie było deklaracji prywatnego konstruktora w klasie Bazowej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1