Methode einer Basisklasse aufrufen / Basisklasse bestimmen



  • Ich habe folgendes (vereinfachtes) Szenario:

    class Basis
    {
        public virtual void write()
        {
            Console.WriteLine("Base");
        }
    };
    
    class spezial1 : Basis
    {
        public override void write()
        {
            Console.Write("Spezial 1 ->");
            base.write();
        }
    
    };
    
    class spezial2 : spezial1
    {
        public override void write()
        {
            Console.Write("Spezial 2 ->");
            base.write();
            //Basis.write(); 
        }
    
    };
    
    namespace asd
    {
        class Program
        {
            static void Main(string[] args)
            {
                Base b;
                spezial1 sp1 = new spezial1();
                spezial2 sp2 = new spezial2();
    
                b = sp1;
                b.write();
                b = sp2;
                b.write();
            }
        }
    }
    

    Spezial 1 -> Base
    Spezial 2 -> Spezial 1 -> Base

    spezial1 macht zu 90% all das was ich benötige. Also klares Ziel um davon zu erben.

    spezial1 hat jedoch in der Methode "write" eine Behandlung der Daten, die für spezial2 nicht anwendbar ist. (Spezial1 kann nur schwer geändert werden, ich kann auch vor Spezial2 kaum Einfluss auf das System nehmen, die Hierarchie ist aber Dokumentiert).

    spezial2.write muss die Daten neu vorbereiten um diese dann an base zu reichen. Der Eingriff von spezial1.write ist unerwünscht. Ich finde jedoch keinen Weg spezial1.write aussen vor zu lassen.

    (Für den Fall das die Beschreibung total vorbei geht:

    Das hier ist gesucht:

    class Base
    {
    	public: virtual void write()
    	{
    		cout<<"Basis"<<endl;
    	}
    };
    
    class spezial1 : public Base
    {
    	public: virtual void write()
    	{
    		cout<<"Spezial 1 -> "<<endl;
    		Base::write();
    	}
    };
    
    class spezial2 : public Base
    {
    	public: virtual void write()
    	{
    		cout<<"Spezial 2 -> "<<endl;
    		Base::write();
    	}
    };
    
    int main(int argc, char* argv[])
    {
    	Base *b;
    	spezial2 sp2;
    	spezial1 sp1;
    
    	b = &sp2;
    	b->write();
    	b = &sp1;
    	b->write();
    
    	return 0;
    }
    

    Spezial 2 -> Basis
    Spezial 1 -> Basis



  • Servus,

    eins habe ich hier jetzt nicht verstanden. Warum erbst du bei Spezial2 von Spezial, wenn du bei Spezial2 nichts von Spezial1 verwenden willst? solltest du hier nicht wie in deinem gesuchten Beispiel von Base erben?

    mfg
    Hellsgore



  • spezial1 macht zu 90% all das was ich benötige. Also klares Ziel um davon zu erben.

    eins habe ich hier jetzt nicht verstanden. Warum erbst du bei Spezial2 von Spezial, wenn du bei Spezial2 nichts von Spezial1 verwenden willst?

    Naja, 90% is mehr als nichts 🤡

    Im Prinzip könnte man diese 90% in ein SpezialBase verschieben und dann Spezial1 und Spezial2 von SpezialBase erben lassen. Für das Projekt wäre es aber einfacher, wenn man die C++ Lösung implementiert bekäme.

    (Ah ich sehe wie Du darauf kommst. Die 90% die ich verwende habe ich der Übersichtlichkeit nicht gepostet, nur eine Beispielmethode um das Problem in einer Compilierfähigen Version zu zeigen.)



  • Servus,

    ahhh.... jetzt verstehe ich... aber ich glaube was du vorhast geht einfach nicht. Im Endeffekt möchtest du in Spezial2 das Base.Base.Write() aufrufen. Also das Write() von deiner Basis Klasse. Allerdings hat die Spezial2 von Spezial1 geerbt, wobei doe Spezial1 die Write Methode schon überschrieben hat. Du hast natürlich jetzt ein dickes Problem an die Base deiner Base Klasse von Spezial2 zu kommen. Ich kenne jetzt nur ein paar wege, via Reflection z.B. oder du übergibts dem Konstruktor von Spezial2 eine Instanz von Basis. Am Schönsten wäre aber nun, wenn du in deiner Spezial1 eine "public virtual void Write2()" machen würdest, in der nur die base.Write() aufgerufen wird. Dann kannst du diese in Spezial2 überschreiben.

    Aber ich sehe das doch richtig, dass hier keine Interfaces im Spiel sind und du auch nur sehr schlecht die Möglichkeit hast, Spezial1 und Basis zu ändern?

    mfg
    Hellsgore

    EDIT: Und er sollte Recht behalten....
    http://msdn.microsoft.com/chats/transcripts/vstudio/05_0811_dn_csharp.aspx

    Mads Torgersen [MS] (Expert):
    Q: why only the first immediate base class is allowed in c#? e.g. cant do base.base.ToString()
    A: The behaviour of your base class is determined by the writer of that class. It would open up a hole for breach of contract if you could bypass this and access something that this writer has decided to hide from you.



  • Hm, ok - ich hatte die Hoffnung das es doch irgendwie geht :o(

    Interfaces sind mir noch etwas Fremd, die Unterlagen die ich hier habe beantworten mir noch nicht alle Fragen die ich dazu habe. (Also weiß ich auch nicht inwieweit mir ein Interface helfen kann.)

    An Base kann geschraubt werden, ich hätte aber nur ungern ein Write2 in allen anderen Klassen.

    An spezial1 kann nur mit viel aufwand geschraubt werden, da ausgerechnet dieser Typ intensiev verwendet wird (Parameterübergabe, cast etc.) .

    (Ich denke noch viel zu viel in C++, mit meiner Factory bin ich auch auf die Nase gefallen. Dort hab ich ein Interface sitzen um die Klassen per Reflection zu identifizieren. Nach dem was ich in den 4 Tagen über C# gelernt habe und in meinen Büchern steht, hätte ich jedoch nicht erwartet, das sich ein Aufruf über das Interface polymoprh verhält, ein virtuell als Modifizierer war nicht erlaubt, es gibt also noch viel zu lernen und umzudenken.)

    thx für den Link!



  • A: The behaviour of your base class is determined by the writer of that class. It would open up a hole for breach of contract if you could bypass this and access something that this writer has decided to hide from you.

    Hm, eigentlich ne halbe Lösung für das Problem. Wenn ich base nicht aufrufe hab ich auch nen "bypass" zu dem was der schreiber vor mir verstecken wollte - wenn ich also mitten in der Vererbung stecke kann ich die Absichten ebenso zerstören. Im Moment sehe ich da irgendwie nicht den Grund (nur meinen Nachteil).

    Und das mit den Interfaces hat sich erledigt 💡



  • Die Lösung ist doch ganz einfach!

    Schreib in deine Basisklasse doch einfach eine 2. Write-Methode (die aber nicht virtuell ist und am besten protected) und standardmäßig von der virtuellen write-Methode aufgerufen wird, also

    class Basis
    {
        public virtual void write()
        {
           real_write();
        }
    
        protected void real_write()
        {
            Console.WriteLine("Base");
        }
    };
    

    Nun einfach von deiner überschriebenen Methode 'write' die Basisklassen-Methode 'real_write' aufrufen.

    So funktionieren gute Interfaces!!!



  • Das is für mich einfach nur ein verhunztes Design weil ich dann nicht mehr von Spezialisierung sprechen kann sondern das gesammte System in Frage stelle.

    Was wenn es dann Spezial3 gibt, die write von Spezial2 überspringen muss und die von spezial1 und base benötigt ?

    AFAIK wird das protected nicht helfen da write_real in in Spezial2 nicht aufgerufen werden kann. (Wurde in Spezial1 zu priavate).

    Macht man es public oder internal hat jede Klasse plötzlich die Möglichkeit write_real aufzurufen und man kann so dringend notwendige Initialisierungen umgehen.

    Das ist für mich kein Funktionierendes Interface. Das ist mehr pfusch als in Spezial1 ne protected bool einzufügen und das entsprechend in spezial1::write zu prüfen. Das kann dann durch Spezial2 angepasst werden. (Aber das ist auch keine Spezialisierung mehr wie ich sie gerne hätte :o( )


Log in to reply