Warum abstract-Schlüsselwort



  • Warum gibt es eigentlich das abstract-Schlüsselwort? Kann man genau diesen Effekt nicht einfach dadurch erzielen, indem man die Konsruktoren der Klasse protected macht?



  • Das ist ein Fall für die Grundlagen.

    http://de.wikipedia.org/wiki/Abstrakte_Klasse



  • Ich weiß, was eine abstrakte Klasse ist. Ich wollte nur wissen, wieso dafür ein eigenes Schlüsselwort benutzt wird, da dasselbe auch mit protected Kontruktoren möglich ist. Man hätte es also weglassen können, ohne Funktionalität oder Programmierkomfort einzubüßen.



  • Alter Falter schrieb:

    Ich weiß, was eine abstrakte Klasse ist. Ich wollte nur wissen, wieso dafür ein eigenes Schlüsselwort benutzt wird, da dasselbe auch mit protected Kontruktoren möglich ist. Man hätte es also weglassen können, ohne Funktionalität oder Programmierkomfort einzubüßen.

    Hätte man nicht. Eine abstrakte Klasse kannst Du nicht (alleine) instanzieren. Eine mit protected CTOR schon (z.B. innerhalb der Klasse oder einer abgeleiteten).
    Simon



  • sieh das am besten eher so

    es ist bei methoden ein "gezwungenes virtual"

    alle klassen die von einer abstracten klasse ergeb _muessen_ die abstracten methoden selber implementieren

    im prinzip ein zwitter aus einer basis klasse die virtuelle methoden bietet und einem interface



  • theta schrieb:

    Hätte man nicht. Eine abstrakte Klasse kannst Du nicht (alleine) instanzieren. Eine mit protected CTOR schon (z.B. innerhalb der Klasse oder einer abgeleiteten).

    Dass man innerhalb der eigenen Klasse instanzieren kann, ist klar. Aber es ist ja auch nicht Sinn der Sache, den Programmierer vor sich selbst zu schützen. Wenn er eine abstrakte Klasse will, dann instanziert er innerhalb dieser Klasse eben kein Objekt.
    Was abgeleitete Klassen betrifft: Das geht nicht. Folgender Code bringt einen Compilerfehler:

    class A
    {
        protected A() { }
    }
    
    class B : A
    {
        public B() { }
    
        public void Funktion()
        {
            A a = new A();
        }
    }
    

    Mr Evil schrieb:

    alle klassen die von einer abstracten klasse ergeb _muessen_ die abstracten methoden selber implementieren

    Das hätte man doch aber auch ohne das abstract-Schlüsselwort erreichen können. (Wenn ich frage, wieso es das abstract-Schlüsselwort gibt, meine ich es natürlich in Bezug auf Klassen. Dass das bei abstrakten Methoden Sinn macht, ist logisch.)



  • Naja, so gesehen kann man auch public / private bei Member Variablen weglassen, denn wenn man halt nicht direkt auf die Member zugreifen soll, tut mans eben nicht.

    Aber genauso wie bei abstract und public / private kann man Ausdrücken (und erzwingen) für was der entsprechende Code gedacht ist und wie er zu gebrauchen ist.

    Simon



  • abstract ist deswegen sinnlos, weil eine Klasse die abstract Funktionen hat automatisch selbst abstract ist. So wie es in C++ auch gelöst wurde.
    Wozu sollte ich da noch die Klasse selbst mit "abstract" markieren müssen?



  • Alter Falter schrieb:

    Aber es ist ja auch nicht Sinn der Sache, den Programmierer vor sich selbst zu schützen.

    Im Gegenteil liegt GENAU darin der Sinn vieler Konstrukte wie public/private, abstract usw.

    1.) Programmierer machen Fehler.
    2.) Programmierer vergessen.

    Je genauer Du dem Compiler sagst was Du willst, desto besser kann dieser Fehler erkennen und melden.

    Im Falle Deines Minimalbeispiels z.B. ist A keine abstrakte Klasse.

    Daher meldet der Compiler auch:

    Cannot access protected member 'A.A()' via a qualifier of type 'A'; the qualifier must be of type 'B' (or derived from it)

    Machst Du dagegen die Klasse A im Beispiel abstract kommt die passende Fehlermeldung:

    Cannot create an instance of the abstract class or interface 'A'

    Aber gehen wir noch einen Schritt weiter indem wir Dein Beispiel vereinfachen:

    class A
        {
            protected A() { }
    
            public static A Create()
            {
                return new A();
            }
        }
    

    Funktioniert einwandtfrei und ohne Compilerwarnung, weil es legitimer Code ist. Und nichtmal abwegig weil dies eine mögliche Implementierung des Factory-Designpatterns ist.

    Dagegen schmeisst folgender Code klar einen Fehler:

    abstract class A
        {
            protected A() { }
    
            public static A Create()
            {
                return new A();
            }
        }
    


  • Alter Falter schrieb:

    Ich weiß, was eine abstrakte Klasse ist.

    Alter Falter schrieb:

    Wenn ich frage, wieso es das abstract-Schlüsselwort gibt, meine ich es natürlich in Bezug auf Klassen. Dass das bei abstrakten Methoden Sinn macht, ist logisch.

    Du hattest in deinem Eingangsbeitrag allgemein gefragt, warum es das abstract-Schlüsselwort gibt.

    Den Default Konstructor protected zu machen ist natürlich möglich, aber nicht Sinn der Sache, höchstens in Verbindung mit abstract.

    Wenn ich mit abstract die komplette Klasse als abstrakt definiere, ist sofort ersichtlich das ich diese Klasse nicht instanzieren kann. Wenn ich nun anfange protected zu verwenden, muss ich alle Konstruktoren protected setzen, sofern keine Methde explizit virtual ist und das ist nunmal nicht Sinn der Sache.



  • theta schrieb:

    Naja, so gesehen kann man auch public / private bei Member Variablen weglassen, denn wenn man halt nicht direkt auf die Member zugreifen soll, tut mans eben nicht.

    Der Vergleich hinkt. private ist dazu da, dem Benutzer der Klasse etwas zu verweigern. abstract im Gegensatz zu einem protected Konstruktor würde nur dazu dienen, dem Ersteller der Klasse vor sich selbst zu schützen.

    loks schrieb:

    Im Gegenteil liegt GENAU darin der Sinn vieler Konstrukte wie public/private, abstract usw.

    1.) Programmierer machen Fehler.
    2.) Programmierer vergessen.

    Wie gesagt: private und public sind Einschränkungen für den Benutzer der Klasse, nicht für den Ersteller. Während abstract nur eine Einschränkung für den Ersteller der Klasse selbst ist, während es für den Benutzer keinen Unterschied gibt zwischen abstrakter Klasse und Klasse mit protected Konstruktor.

    loks schrieb:

    Je genauer Du dem Compiler sagst was Du willst, desto besser kann dieser Fehler erkennen und melden.

    Es mag vielleicht ein kleiner Komfort sein, aber welcher Programmierer designt eine abstrakte Klasse und erstellt dann später innerhalb der Klasse ein Objekt davon? Im Prinzip könnte ich jetzt auch sagen: private ist dafür da, dass von außerhalb nicht auf ein Attribut zugegriffen werden kann. Aber sowas geht trotzdem:

    class X
    {
        private var;
    
        public Funktion(X x)
        {
            var = x.var;
            //Zugriff von "außen" auf ein privates Atrribut.
        }
    }
    

    Nach deiner Logik könnte ich jetzt auch verlangen, dass es noch einen Zugriffsmodifizierer "really_private" gibt, der den Ersteller der Klasse dazu zwingt, auch wirklich nur von innerhalb der Klasse auf die Attribute des zu erstellenden Objekts zuzugreifen. Und nicht auf die Attribute eines anderen Objekts, das nur zufällig zur selben Klasse gehört.

    loks schrieb:

    Im Falle Deines Minimalbeispiels z.B. ist A keine abstrakte Klasse. ... Machst Du dagegen die Klasse A im Beispiel abstract kommt die passende Fehlermeldung:

    Ändert nichts daran, dass die Aussage von theta (man könne in einer abgeleiteten Klasse ein Objekt der Basisklasse erstellen, selbst wenn deren Konstruktoren protected sind) falsch ist.

    loks schrieb:

    Aber gehen wir noch einen Schritt weiter indem wir Dein Beispiel vereinfachen:

    class A
        {
            protected A() { }
    
            public static A Create()
            {
                return new A();
            }
        }
    

    Funktioniert einwandtfrei und ohne Compilerwarnung, weil es legitimer Code ist. Und nichtmal abwegig weil dies eine mögliche Implementierung des Factory-Designpatterns ist.

    Dagegen schmeisst folgender Code klar einen Fehler:

    abstract class A
        {
            protected A() { }
    
            public static A Create()
            {
                return new A();
            }
        }
    

    Ja, aber wie gesagt: Wenn der Programmierer so eine Create-Funktion erstellt, dann will er ja auch gar keine abstrakte Klasse haben. Also würde zweitere Situation nie auftreten: "Hey, lass uns eine Create-Funktion machen...Ach ja, stimmt: Die Klasse soll ja abstrakt sein. Hab ich ganz vergessen. Mann, zum Glück gibt es das abstract-Schlüsselwort. Hätte ich das nicht gehabt, dann hätte er doch eben beinahe den Code durchgelassen." Wer eine Create-Funktion schreibt, obwohl er die Klasse als abstrakt gedacht hat, dem ist eh nicht mehr zu helfen.

    loks schrieb:

    Du hattest in deinem Eingangsbeitrag allgemein gefragt, warum es das abstract-Schlüsselwort gibt.

    Stimmt. ich hatte vergessen, zu erwähnen, dass ich nur die klassenbezogende bedeutung meine. Denn abstract in Verbindung mit einer Funktion ist ja dann logischerweise wieder etwas, das man nicht mit anderen Mitteln nachbauen kann, und was deshalb sinnvoll ist.

    loks schrieb:

    Den Default Konstructor protected zu machen ist natürlich möglich, aber nicht Sinn der Sache, höchstens in Verbindung mit abstract.

    Wenn ich mit abstract die komplette Klasse als abstrakt definiere, ist sofort ersichtlich das ich diese Klasse nicht instanzieren kann. Wenn ich nun anfange protected zu verwenden, muss ich alle Konstruktoren protected setzen, sofern keine Methde explizit virtual ist und das ist nunmal nicht Sinn der Sache.

    Und wo ist das Problem? Einen Zugriffsmodifizierer muss der Konstruktor doch sowieso haben, wenn er nicht private sein soll. Also ist das doch keine Mehrarbeit. Viel komischer finde ich es, wieso ich in einer als abstract markierten Klasse den Konstruktor trotzdem noch auf public oder protected setzen kann. Wo ist da der Sinn? Was ist der Unterschied zwischen

    abstract class X
    {
        public X() { }
    }
    

    und

    abstract class X
    {
        protected X() { }
    }
    

    ?



  • Alter Falter schrieb:

    Und wo ist das Problem? Einen Zugriffsmodifizierer muss der Konstruktor doch sowieso haben, wenn er nicht private sein soll. Also ist das doch keine Mehrarbeit.

    Es geht nicht um Mehrarbeit, es geht um Klarheit. Mit abstract kann ich deutlich die komplette Klasse als abstrakt deklarieren ohne explizit mir Gedanken um die Konstruktoren zu machen.

    Alter Falter schrieb:

    Viel komischer finde ich es, wieso ich in einer als abstract markierten Klasse den Konstruktor trotzdem noch auf public oder protected setzen kann. Wo ist da der Sinn? Was ist der Unterschied zwischen

    abstract class X
    {
        public X() { }
    }
    

    und

    abstract class X
    {
        protected X() { }
    }
    

    ?

    In C# ist der Default-Konstruktor auch automatisch immer protected, sobald die Klasse abstract ist. In vielen Fällen wird nämlich überhaupt kein Konstruktor implementiert.

    Falls ein Konstruktor implementiert wird um Initialisierungen etc. vorzunehmen, dann ist es sogar ein guter Codestil, den Konstruktor einer abstrakten Klasse zusätzlich mit protected zu versehen, weil es zeigt das nur die abgeleitete Klasse sie instanzieren kann. Natürlich macht es dann keinen Sinn den Konstruktor auf public zu stellen.


Anmelden zum Antworten