Konstruktor einer abstrakten Klasse



  • Hallo, ich programmiere zwar schon seit einige Zeit in C, aber C++ mache ich erst seit kurzem. Mein jetziges Projekt läuft langsam aus den Ruder, weshalb ich mich jetzt mit Entwurfsmustern beschäftige. Es scheint, das das Fabrikmuster auf mein Problem passt. Aber leider werden in den gängigen Büchern nur Java Beispiele angeführt.

    Ich stehe jetzt also vor dem Problem in C++ eine abstrakte Klasse erstellen zu müssen, die einen Konstruktor benötigt. Wie mache ich das? Ich kann ja wohl schlecht einen virtuellen Konstruktor definieren.

    Meine bisherige "Super-" Klasse hat etwa 5 unterschiedliche Konstruktoren, was nicht gerade übersichtlich ist.

    Konkret handelt es sich um digitale Filter, die je nach Typ und Designmethode unterschiedliche Angaben zur Erstellung benötigen.

    Kann mich da jemand auf die richtige Spur bringen?



  • einwegflasche schrieb:

    Wie mache ich das?

    Genauso wie in Java.



  • Warum braucht die abstrakte Klasse einen Konstruktor? Warum glaubst du, dieser müsse virtuell sein?



  • Die Beispiele im Gang of Four Buch sind (hoffentlich auch in aktuellen Ausgaben) in C++ geschrieben.



  • manni66 schrieb:

    Warum braucht die abstrakte Klasse einen Konstruktor? Warum glaubst du, dieser müsse virtuell sein?

    Warum sollte eine abstr. Klasse keinen Ctor benötigen oder haben dürfen? 😕
    Er hat ja nichts von purer abstr. Klasse geschrieben (was in Java einem Interface entsprechen würde).



  • einwegflasche schrieb:

    Ich stehe jetzt also vor dem Problem in C++ eine abstrakte Klasse erstellen zu müssen, die einen Konstruktor benötigt. Wie mache ich das? Ich kann ja wohl schlecht einen virtuellen Konstruktor definieren.

    Einfach die Konstruktoren definieren. Und in der Subklasse kann man die dann aufrufen (anstatt super(x) den MySuperClass(x)).

    http://www.kharchi.eu/885/virtuelle-konstruktoren

    einwegflasche schrieb:

    Meine bisherige "Super-" Klasse hat etwa 5 unterschiedliche Konstruktoren, was nicht gerade übersichtlich ist.

    Muss nicht falsch oder schlecht sein.

    Konkret handelt es sich um digitale Filter, die je nach Typ und Designmethode unterschiedliche Angaben zur Erstellung benötigen.

    Welche Factory hast du dir denn raus gesucht? Factory ist ein sehr allgemeiner Begriff, es gibt ja mehrere.



  • Artchi schrieb:

    manni66 schrieb:

    Warum braucht die abstrakte Klasse einen Konstruktor? Warum glaubst du, dieser müsse virtuell sein?

    Warum sollte eine abstr. Klasse keinen Ctor benötigen oder haben dürfen? 😕
    Er hat ja nichts von purer abstr. Klasse geschrieben (was in Java einem Interface entsprechen würde).

    Ich habe nicht behauptet, dass sie keinen haben darf.



  • Ich sagte ja, das ich C++ noch nicht so lange mache. Daher bin ich davon ausgegangen, das eine Klasse einen Konstruktor haben muss.

    Artchi schrieb:

    Muss nicht falsch oder schlecht sein.

    Das bedeutet aber, dass das Hauptprogramm alle Varianten der Konstruktoren kennen muss. Momentan muss ich bei Änderungen immer mehrere Module gleichzeitig anfassen.

    Welche Factory hast du dir denn raus gesucht?

    Die einfachste, also nicht die abstrakte, mehr kenne ich nicht.

    Aber vielleicht gibt es ja noch eine bessere Methode. Denn die Entwurfsparameter müssen ja auch irgendwo herkommen. Aber ich denke das könnte die Factory auch erledigen.



  • Das bedeutet aber, dass das Hauptprogramm alle Varianten der Konstruktoren kennen muss. Momentan muss ich bei Änderungen immer mehrere Module gleichzeitig anfassen.

    Ja, dann musst du abstrahieren in dem du gegen Interfaces bzw. (pure) abstrakte Klassen programmierst.

    Hinter der Factory verbergen sich dann die konkreten Implementierungen. Und die Module benutzen nur die abstraktionen, und die Factory entscheidet was sie konkret (abgeleitete/spezielle Klasse) raus gibt.

    Das kannst du schon mit einer Simple Factory erreichen. Ganz banal (DUMMY Code):

    // factory.h
    #include "BaseClass.h"
    
    unique_ptr<BaseClass> create_object(const string &type);
    
    // factory.cxx
    #include "TypeA"
    #include "TypeB"
    
    unique_ptr<BaseClass> create_object(const string &type) {
      if( type == "A" )
         return make_unique<TypeA>(); // evtl. mit Konstruktor-Parametern
      else if( type == "B" )
         return make_unique<TypeB>();
    }
    

    Es ist dann auch kein Problem später die konkreten Typen zu ändern oder sogar auszutauschen: anstatt TypeB könnte auch TypeB2 zurück gegeben werden. Die fremde Module inkludieren aber nur factory.h und bekommen nichts mit.
    Anstatt Typen kannst du auch einfach unterschiedliche Konstruktoren von einem Typ aufrufen.
    Das TypeA und TypB von BaseClass ableiten müssen, ist aber selbstverständlich. 😉

    Ich hatte dir oben in meinem zweiten Beitrag aber schon einen Link auf einen Blog-Eintrag zu einer leistungsfähigeren Factory gepostet.



  • einwegflasche schrieb:

    Konkret handelt es sich um digitale Filter, die je nach Typ und Designmethode unterschiedliche Angaben zur Erstellung benötigen.

    Das Berechnen der Filterkoeffizienten ist IMO nicht Aufgabe einer Filter-Klasse.
    D.h. mach dir Funktionen (z.B. einfach freie Funktionen, bzw. evtl. auch Member einer darauf spezialisierten Klasse), die dir Filterkoeffizienten berechnen.
    Die Filter-Klasse braucht dann bloss noch einen Ctor, der z.B. ne struct mit den Filterkoeffizienten bekommt.



  • Ist zwar noch nicht fertig, aber so ähnlich habe ich das jetzt angefangen.

    Zuerst eine abstrakte Basisklasse 'Filter' mit leerem Konstruktor und Destruktor.

    Auf die andere Seite kommen dann ca. 15 Klassen, wo dann die Berechnung der individuellen Parameter stattfindet.

    Dazwischen habe ich dann noch etwa 3 Klassen, die nur den ausführenden Code bereit stellen. (Der ist z.B. für alle FIR Filter gleich)

    Heute Mittag konnte ich das erste Codestück fehlerfrei Übersetzen, aber ob das auch funktioniert muss sich noch zeigen.

    Ich hatte dir oben in meinem zweiten Beitrag aber schon einen Link auf einen Blog-Eintrag zu einer leistungsfähigeren Factory gepostet.

    Da war ich wohl noch nicht so weit. Ich steige erst jetzt langsam dahinter wie das funktionieren soll. Der Umstieg von C nach C++ ist nicht so einfach, jedenfalls wenn man die Möglichkeiten von C++ auch nutzen will.



  • Das Berechnen der Filterkoeffizienten ist IMO nicht Aufgabe einer Filter-Klasse.

    Das ist auf der einen Seite richtig, aber die Koeffizienten müssen ja irgendwie in die Klasse kommen und der Zugriff soll zur Laufzeit nicht so kompliziert sein. Bisher sieht das etwa so aus:

    //-----------------------------------------------------------------------------
    //      FIR low pass
    FIR_lpf::FIR_lpf( int type, int taps, double f1 ) : F_fir_df2() {
        int     n;
        int     i;
        double  lambda;
        double  mm;
    
        fi_type = type;
        num_taps = taps;
        b       = new double[num_taps];
        inbuf   = new double[num_taps];
        ix      = 0;
        lambda  = 2.0 * M_PI * f1;
        i = num_taps - 1;   // tap coefficients are stored in reversed order!
        for( n = 0; n < num_taps; n++ ) {
            mm = n - (num_taps - 1.0) / 2.0;
            if( mm == 0.0 )
                b[i] = lambda / M_PI;
            else
                b[i] = sin( mm * lambda ) / (mm * M_PI);
            i--;
        }
        m_delay = num_taps / 2;
    }
    

    Die Filter-Klasse braucht dann bloss noch einen Ctor, der z.B. ne struct mit den Filterkoeffizienten bekommt.

    Da muss ich nochmal drüber nachdenken.


Log in to reply