Möglichkeit eine Member-Funktion davor zu "schützen" in ABgeleiteten Klassen überdeckt zu werden.



  • Naja, man kann höchstens die ganze Klasse "final" machen, über den "virtual inheritance trick":

    class final_helper
    {
    private:
        friend class final;
        final_helper() {}
    };
    
    class final : virtual private final_helper {
    public:
        final() {}
    };
    
    class test : public final {}; // geht nicht, da kein Zugriff auf final_helper::final_helper
    

    Der VC 2005 compiliert das noch ohne Probleme, allerdings spuckt er sobald du versuchst ein "test" anzulegen. IMHO sollte er schon ohne das spucken, aber naja.


  • Mod

    hustbaer schrieb:

    IMHO sollte er schon ohne das spucken, aber naja.

    Warum? Der implizit deklaratierte Konstruktor wird erst implizit definiert, sobald er benutzt wird. Die Klassendefinition als solche ist ja nicht verkehrt.



  • HumeSikkins schrieb:

    Überdeckung schließlich kannst du nicht verhindern. Wenn jemand in der abgeleiteten Klasse eine Methode definieren möchte, die den selben Namen wie deine Basisklassenmethode besitzt, gibt es nichts, was du dagegen tun kannst.

    hmm.. schätze das ist ziemlich genau das, was ich gemeint hab.

    mein Problem ist z.Zt. vor allen Dingen, daß ich eine Klasse habe, sehr auf Geschwindigkeit ausgelegt ist und alles mögliche Initialisierungszeugs muss ersteinmal aufgerufen werdne, bevor man sie verwenden kann... Ich traue jemandem, der meine API benutzt nicht zu, bestimmte virtuelle Funktionen so zu überschreiben (sorry wg. überladen vs überschreiben, bin in Deutsch was programmieren angeht nich so fitt. Kann das alles nur auf Englisch), daß es keine Probleme mit der Initialisierung gibt, ohne daß er die sources kennt (die wir aber unter Verschluß halten wollen, da er firmenintern gebraucht wird)

    Schade, daß der "virtual inheritance Trick" nur füpr ganze Klassen funktioniert... mal gucken vielleicht krieg ich irgendwas gebastelt mit makros, und sonstigen Sachen...

    Grüße, Tom und danke für die Antworten



  • yeus schrieb:

    ...Ich traue jemandem, der meine API benutzt nicht zu, bestimmte virtuelle Funktionen so zu überschreiben ... daß es keine Probleme mit der Initialisierung gibt, ohne daß er die sources kennt ...

    Dann würde ich nochmal das Design Deiner Initialisierung überdenken. Wenn es so kompliziert ist, solltest Du evtl. eine eigene "Initialisiererklasse" diese Arbeit übernehmen lassen. Entweder kannst Du die dann gefahrloser veröffentlichen oder Du stattest sie mit genügend Intelligenz aus, dass sie selbst dafür sorgen kann, dass alles klappt.

    Alternativ könntest Du auch Deiner Klasse zum Initialisieren verschiedene Funktionen Init1(), Init2(), .... o.ä. geben, die eine ordentliche Initialisierung stärker nahelegen....

    ... und natürlich gehört eine ordentliche Dokumentation oder gar Schulung dazu. Bestimmte Themen sind einfach derartig komplex, dass man sie mit aller Liebe zum User nicht weiter vereinfachen kann. Da hilft dann nur entsprechende Schulung/Support.

    - zumindestens mein Vorschlag ohn Kenntnisse Deines speziellen Problems/Codes.

    Gruß,

    Simon2.



  • hustbaer schrieb:

    "virtual inheritance trick":...

    In ein template kann man das aber nicht packen, oder ?
    Irgendwie stört da das "class" in der friend Deklaration ...

    Oder geht das doch ?

    Gruß,

    Simon2.


  • Mod

    Simon2 schrieb:

    hustbaer schrieb:

    "virtual inheritance trick":...

    In ein template kann man das aber nicht packen, oder ?
    Irgendwie stört da das "class" in der friend Deklaration ...

    Oder geht das doch ?

    Gruß,

    Simon2.

    Nein, geht nicht, weil in friend Deklarationen bestimmte Arten abhängiger Typen (insbesondere Templateparameter selbst) unzulässig sind.



  • Schade !

    Aber nungut, geht eben nicht alles.

    Danke für die Antwort,

    Simon2.



  • yeus schrieb:

    mein Problem ist z.Zt. vor allen Dingen, daß ich eine Klasse habe, sehr auf Geschwindigkeit ausgelegt ist und alles mögliche Initialisierungszeugs muss ersteinmal aufgerufen werdne, bevor man sie verwenden kann... Ich traue jemandem, der meine API benutzt nicht zu, bestimmte virtuelle Funktionen so zu überschreiben (sorry wg. überladen vs überschreiben, bin in Deutsch was programmieren angeht nich so fitt. Kann das alles nur auf Englisch), daß es keine Probleme mit der Initialisierung gibt, ohne daß er die sources kennt

    Ich verstehe nicht wirklich, wo das Problem ist. Warum setzt du nicht einfach das Non-virtual-interface-Pattern ein? Also nicht-virtuelle (und damit nicht überschreibbare Methoden), die irgendwelche Pre-/Post-Conditions sicherstellen und dazwischen irgendwelche, als privat deklarierte, virtuelle Methoden aufrufen.

    So kannst du sicherstellen, dass Basisklassencode garantiert aufgerufen wird, bleibst aber trotzdem erweiterbar.



  • Schade, daß der "virtual inheritance Trick" nur füpr ganze Klassen funktioniert... mal gucken vielleicht krieg ich irgendwas gebastelt mit makros, und sonstigen Sachen...

    Ich würde sagen gottseidank dass der nur für Klassen funktioniert, sonst würde man diesen greislichen Hack viel zu oft sehen. Und schön ist das nun wirklich nicht.

    Wirklich schade finde ich dass es in C++ kein "final" gibt...
    Und kein "finally", und kein... ach da könnte ich noch länger weiter machen 🙂

    @camper: Wie es aussieht hast du Recht (vonwegen impliziter ctor - mit nem expliziten ctor spuckt VS 2005 auch sofort). Irgendwie hat es auch eine gewisse seltsame Logik dass es so ist wie es ist, aber "intuitiv" finde ich es nicht 😉



  • hustbaer schrieb:

    Wirklich schade finde ich dass es in C++ kein "final" gibt...

    Warum? Was genau bringt dir final? Protecting gegen Machiavelli? In C++ gibt es ein ganz einfaches final: lass die virtuellen Methoden weg (insbesondere beim Dtor). Das hindert natürlich niemanden daran, von der Klasse abzuleiten. Es signalisiert aber jedem halbwegs gebildeten C++ Programmierer, dass die Klasse nicht als Basisklasse gedacht ist. Ich halte das für völlig ausreichend: schließlich geht es um Programmierung und nicht um Erziehung.

    Und kein "finally"

    Den Sinn von finally sehe ich in C++ auch nicht. Entweder finally oder garantierte Destruktoraufrufe. Eins von beiden erscheint mir völlig ausreichend zu sein.



  • Den Sinn von finally sehe ich in C++ auch nicht. Entweder finally oder garantierte Destruktoraufrufe. Eins von beiden erscheint mir völlig ausreichend zu sein.

    Es ist halt oft lästig sich diverse Guard Klassen schreiben zu müssen für gewisse Dinge. z.B. Änderungen an Daten die 2 oder 3 Schritte brauchen, wo jedesmal eine Exception fliegen kann. Dann muss man da blöd eine "undo" Klasse schreiben um die bereits gemachten Änderungen wieder rückgängig zu machen (im Destruktor, falls eben eine Exception beim 2. oder 3. Schritt fliegt), damit nachher alles wieder konsistent ist. Mit finally geht das IMHO oft wesentlich eleganter.



  • hustbaer schrieb:

    ...
    Wirklich schade finde ich dass es in C++ kein "final" gibt...

    Mal abgesehen davon, dass ich es auch konsistenter fände, wenn man in C++ die "Ableitbarkeit von Klassen" explizit angeben (oder meinetwegen auch verbieten) könnte: In welchem konkreten Fall hast Du das denn vermisst ?

    Ich frage, weil wir gerade auf der Arbeit darüber diskutiert haben .... (wohlgemerkt, ich hätte auch gern ein "final für Vererbung" in C++, aber mir fiel kein Beispiel dafür ein, wo ich das wirklich sinnvoll einsetzen wollte/müsste/...)

    Gruß,

    Simon2.

    P.S.: Für ein "finally" sehe ich aber auch keinen Grund, wenn man denn Destruktoren hat ... Dtoren finde ich da "besser". 😃



  • Was bringt dir denn das Verbieten davon? Richtig: gar nichts, weil du dich damit nicht ärger musst sondern derjenige der sich nicht an deine Anweisungen hält.



  • lolz schrieb:

    Was bringt dir denn das Verbieten davon? Richtig: gar nichts, weil du dich damit nicht ärger musst sondern derjenige der sich nicht an deine Anweisungen hält.

    Es reicht mir schon wenn Leute zu mir kommen und fragen wieso irgendwas nicht geht, bloss weil sie die Doku nicht gelesen haben, oder einfach nicht geguckt haben was für ein Kommentar neben dem assert() steht, bzw. wie die Bedingung des assert() aussieht.

    Und da reicht nichtmal ein

    assert(0 && "You cannot do XYZ with this ABC instance because FOO")
    

    Allerdings muss ich zugeben dass ich "final" bei der täglichen Arbeit lange nicht so sehr vermisse wie andere Dinge.

    -----

    Zum thema "finally" poste ich (wenn ich nicht vergesse) heute Abend noch ein Beispiel.


Anmelden zum Antworten