Virtuelle Überladene Funktionen, Warnung vom Compiler?



  • Hallo Forum

    Frage zu Überladenen virtueller Funktionen

    Kurz das Problem als Beispiel.

    class Base
    {
    public:
     virtual void serialize(ostream &out);
     virtual void serialize(ostream &out, bool child);
    };
    
    class Wichtig : public Base
    {
    public:
     virtual void serialize(ostream &out);
    };
    

    Jetzt mahnt mich der Compiler an das die zweite Funktion in der Klasse base von der ersten Funktion in der Klasse Wichtig versteckt wird. (hidden)
    Compelieren lässt sich das und funktioniert auch. (Beide Funktionen über Klase Wichtig aufzurufen)

    Jetzt die Frage:
    Ist das ein Fehler vom Code, eine Überflüssige Meldung vom Compier oder nur ein schlechter Still, worauf mich der compiler aufmerksam machen will.

    Lichtlein


  • Mod

    Wenn ich nicht irgendeine Sonderklausel im Standard für virtuelle Funktionen übersehen habe, dann hat das nichts mit virtual zu tun, sondern ist das normale Verhalten für überladene Funktionen. Denn Überladung funktioniert nur im gleichen Scope und der Scope von Klassen die voneinander erben ist nicht gleich.

    Beispiel aus dem Standard (Kapitel 13.2):

    class B {
    public :
     int f ( int );
    };
    class D : public B {
    public :
     int f ( char *);
    };
    

    Hier wird B::f(int) von D::f(char*) verdeckt, nicht überladen.

    Der Compiler warnt dich, weil das eventuell nicht das Verhalten ist was du wünscht und du die Funktion serialize(ostream &, bool) von einem Wichtig-Objekt aus nicht mehr ohne weiteres aufrufen kannst.



  • So ganz zufrieden bin ich mit der Antwort nicht oder verstehe nicht ganz die Logic dahinter. Werde mich wohl aber damit abfinden müssen und solche Konstrukte nicht mehr machen.

    Danke schön
    Lichtlein


  • Mod

    Frag ruhig genau nach, wenn du etwas nicht verstehst.

    Wenn du nur sagst, dass du etwas nicht verstehst, kann ich dir auch nicht weiterhelfen.


  • Mod

    Lichtlein schrieb:

    Jetzt mahnt mich der Compiler an das die zweite Funktion in der Klasse base von der ersten Funktion in der Klasse Wichtig versteckt wird. (hidden)
    Compelieren lässt sich das und funktioniert auch. (Beide Funktionen über Klase Wichtig aufzurufen)

    Das ist ein bisschen unpräzise.
    Untersuchen wir einfach mal alle Möglichekeiten eines direkten Funktionsaufrufes:

    Wichtig x( ... );
    Base& y = x;
    
    x.serialize(cout); // ok
    x.serialize(cout, true); // Fehler: diese Überladung wird verdeckt
    
    y.serialize(cout); // ok
    y.serialize(cout, true); // ok
    
    x.Wichtig::serialize(cout, true); // ok
    

    Sind virtuelle Funktionen im Spiel, werden Aufrufe typischerweise über das Interface der Basisklasse ausgeführt, damit spielt die Verdeckung dann keine Rolle.
    Die allgemein empfohlene Abhilfe besteht in einer entsprechenden using Deklaration:

    class Wichtig : public Base
    {
    public:
     using Base::serialize; // damit werden alle Deklaration der aus Base geerbten serialize Funktionen in den Scope der Klasse Wichtig injiziert
     virtual void serialize(ostream &out);
    };
    


  • Ok, bei Deinen Beispiel kann ich das noch nachvollziehen.
    Eine Funktion mit 1 Parameter der aber unterschiedlich ist.

    Aber bei den Virtuellen Funktionen nicht mehr.

    Der Compiler muss ja für jede Funktion in den Sprungtabellen einen Eintrag machen.

    (vtable) fuer Klasse Base
    {func0] Base::~Base()
    [func1] Base::serialize(ostream &Out)
    [func2] Base::serialize(ostream &Out, bool Child)
    [func3] ....
    

    Nun macht er die vtable fuer Klasse Wichtig

    (vtable) fuer Wichtig
    {func0] Wichtig::~Wichtig()
    [func1] Wichtig::serialize(ostream &Out)
    [func2] Base::serialize(ostream &Out, bool Child)
    [func3] ....
    

    Findet der Compiler im Source die Stelle

    serialize(cout);
    

    und dann

    serialize(cout, true);
    

    kann er sie zu 100% richtig zuordnen. Also bedarf es keiner Warnung.

    Ich kann mir aber denken das ausgehend von Deinen Beispiel, wo die Warnung angebracht ist, nicht noch einen Sonderregelung/Sonderüberprüfungen für Virtuelle/Überlade/Vererbte Funktionen erdacht worden ist, sondern der Compiler einfach eine Warnung schmeißt obwohl hier immer zu 100% Richtig aufgelöst werden kann.

    Lichtlein



  • @camper

    Oh danke, ich habe das jetzt selber ausprobiert.
    Genau wie du geschrieben hast.

    Habe dann noch mal meine Sourcen überflogen und die Stellen gesucht wo der Compiler nur eine Warnung gebracht hatte. (Waren etwa 10) Wie es der zufall will wurde immer nur die Funktion aufgerufen die auch virtual vererbt worden war. 🙂
    Und die andere Funktion wurde nur aus der base Klasse benutzt. Wurde ich dadurch auf die falsche Fährte geführt.

    Übrigens, das mit den using ist eine gute idee. Denke nie dran das man auch funktionsnamen damit aufsetzen kann.

    Lichtlein


Anmelden zum Antworten