Konstante in Klasse übergeben



  • Hallo!
    So, mein Programm läuft erstmal, aber ich wollte den Code noch etwas schöner machen. Dabei stoß ich allerdings an meine Grenzen: Ich habe eine Konstante, mit der ich per Konstruktor eine Variable einer Klasse initialisiere:

    Fft kugel(FFT_LAENGE);
    

    und der Konstruktor:

    Fft(const long konstr_laenge):LAENGE(konstr_laenge){
     }
    
    ...
    
    long LAENGE;
    

    Innerhalb der Klasse bräuchte ich die Variable eigentlich auch nur als Konstante, aber mir fällt keine Möglichkeit ein, diese Konstante dann Klassenweit zur Verfügung zu stellen. Das eigentliche Problem ist jetzt, das ich innerhalb der Klasse Fft Variablen habe, welche LAENGE für ihre Definition als Konstante benötigen. Also z.B:

    double data[LAENGE];
    

    Solang LAENGE eine Variable ist, beschwert sich der Compiler (verständlicherweise), das er mir mit der Variablen kein Feld baut. Was macht man in so einem Fall? Oder ist mein Konzept einfach zu mies? Sämtliche cast und Pointerideen, die ich bis jetzt hatte, sind gescheitert. Weiß schon gar nicht mehr, was ich alles versucht habe...



  • Du brauchst nicht nur eine Konstante, sondern eine statische Konstanten.

    class Fft {
    static const long LAENGE = 2;
    
    long a[LAENGE];
    }
    

    Somit kannst du die Länge nicht für jedes Objekt mitangeben.
    Aber was du machen kannst, ist dir mal std::vector anschauen. Da stellt sich diese Frage gar nicht erst.



  • Innerhalb der Klasse bräuchte ich die Variable eigentlich auch nur als Konstante, aber mir fällt keine Möglichkeit ein, diese Konstante dann Klassenweit zur Verfügung zu stellen.

    class Fft
    {
        public:
            Fft(const long konstr_laenge):LAENGE(konstr_laenge){ }
        private:
            const long LAENGE;    // nun ist die Variable Klassenweit bekannt
    }
    

    Solang LAENGE eine Variable ist, beschwert sich der Compiler (verständlicherweise), das er mir mit der Variablen kein Feld baut. Was macht man in so einem Fall?

    einen pointer nehmen 🙂

    Sämtliche cast und Pointerideen, die ich bis jetzt hatte, sind gescheitert.

    Es wäre sicherlich amüsant diese zu sehen 🙂
    warum nicht so:

    double data = new double( LAENGE );
    

    ?



  • double *T schrieb:

    Fledi schrieb:

    Sämtliche cast und Pointerideen, die ich bis jetzt hatte, sind gescheitert.

    Es wäre sicherlich amüsant diese zu sehen 🙂

    Wer im Glashaus sitzt... SCNR

    double *T schrieb:

    warum nicht so:

    double data = new double( LAENGE );
    

    ?

    Weil's quatsch ist? Damit bekämst Du - wenn sich der Compiler *denken würde*, dass data ein Pointer ist, 1 (in Worten: eine) double die mit LAENGE initialisiert wird.

    warum nicht so:

    double *data( new double[ LAENGE ] );
    
    // oder wahlweise natürlich:
    
    double *data = new double[ LAENGE ];
    

    ?

    cheers, Swordfish

    PS:

    nicht vergessen!



  • Danke erstmal für die Antworten. Das bringt mich auf jeden Fall ein Stück weiter.

    @ drakon: Static bringt leider nix, weil ich den Wert von LAENGE auf jeden Fall von außen kriege. Und wenn ich eine Variable im Konstruktor als static deklariere, bleibt sie zwar erhalten, steht mir aber außerhalb des Konstruktors nicht zur Vefügung...
    Aber std::vector sieht ganz gut aus. Warscheinlich wirds das werden...

    @double *T:

    class Fft
    {
        public:
            Fft(const long konstr_laenge):LAENGE(konstr_laenge){ }
        private:
            const long LAENGE;    // nun ist die Variable Klassenweit bekannt
    }
    

    Gut, hier hatte ich mich falsch ausgedrückt. Das war mein allererster Ansatz. Nur das er mir dann eben eine "ungültige Verwendung des nicht-statischen Datenelementes "FFT::LAENGE" " zurückgibt, sobald ich meine Felder basteln will...

    Es wäre sicherlich amüsant diese zu sehen 🙂

    Nö 😛

    @ swordfish:

    warum nicht so:

    double *data( new double[ LAENGE ] );
    
    // oder wahlweise natürlich:
    
    double *data = new double[ LAENGE ];
    

    ?

    Öhmm...wär ja schön gewesen, aber nein 😞
    Ich will nicht sagen, das ch es hundertprozentig verstehe, aber wenn ich das so definiere, sagt er mir "Fft::LAENGE kann nicht in Konstanten-Ausdruck auftreten"
    und "'new' kann nicht in Konstanten-Ausdruck auftreten", egal ob ich LAENGE als const definiere oder nicht...



  • Dann schreib halt nur double *data; und im Konstruktor (wo du Laenge ja hast) data = new double[LAENGE]; und im Destruktor entsprechend delete[] data;



  • @ drakon: Static bringt leider nix, weil ich den Wert von LAENGE auf jeden Fall von außen kriege. Und wenn ich eine Variable im Konstruktor als static deklariere, bleibt sie zwar erhalten, steht mir aber außerhalb des Konstruktors nicht zur Vefügung...
    Aber std::vector sieht ganz gut aus. Warscheinlich wirds das werden...

    Bitteschön:

    class foo 
    {
    public:
    	foo (int n)
    		:a (new int [n] )
    	{
    	}
    	~foo ()
    	{
    		delete [] a;
    	}
    
    private:
    	int* a;
    };
    

  • Mod

    Copy-ctor und Zuweisung immer gleich mit dazu.

    class foo
    {
    public:
        explicit foo (int n)
            :n_(n), a_(new int [n]())
        {
        }
        ~foo ()
        {
            delete [] a;
        }
        foo (const foo& other)
            :n_(other.n_), a_(new int [other.n_])
        {
            std::copy( other.a_, other.a_ + n_, a_ );
        }
    // fehleranfällig und dupliziert Code:
    /*    foo& operator=(const foo& rhs)
        {
            int* p = new int [other.n_];
            std::copy( other.a_, other.a_ + other.n_, p );
            n_ = other.n_;
            delete [] a_;
            a_ = p;
            return *this;
        }*/
    // einfach(er und) besser
        foo& operator=(foo rhs)
        {
            swap( rhs );
            return *this;
        }
        void swap(foo& other)
        {
            std::swap( n_, other.n_ );
            std::swap( a_, other.a_ );
        }
    private:
        int n_;
        int* a_;
    };
    


  • camper schrieb:

    foo& operator=(foo rhs)
        {
            swap( rhs );
            return *this;
        }
    

    Warum machst du es auf die Art? Ist imho nicht so schnell als copy&swap zu erkennen, wie auf die andere Art mit der Kopie im inneren.



  • Wenn das Array in seiner Länge zur Compilezeit auf jeden Fall bekannt ist, und die Länge sich auch zur Laufzeit nicht ändern wird, kann man auch ein Template nehmen:

    template<size_t LENGTH>
    class Ftw
    {
    public:
        //...
    private:
        double data[LENGTH];
    };
    
    //...
    Ftw<128> ftw
    

  • Mod

    drakon schrieb:

    camper schrieb:

    foo& operator=(foo rhs)
        {
            swap( rhs );
            return *this;
        }
    

    Warum machst du es auf die Art? Ist imho nicht so schnell als copy&swap zu erkennen, wie auf die andere Art mit der Kopie im inneren.

    Ich dürfte aber einfach nur ein Gewöhnungseffekt sein. Es rührt eher prinzipiell an der Frage, ob Argument, die in jedem Falle kopiert werden müssen, nicht besser gleich per Value übergeben werden sollten. Die hier gezeigte Version hat einen handfesten Vorteil: die Kopie kann, falls das Argument selbst temporär ist, per RVO wegoptimiert werden (man bekommt also einen Fast-Move-Operator ohne etwas dafür zu zahlen), das ist nicht möglich, wenn die Kopie erst innerhalb der Funktion erfolgt. Beispiel

    foo func();
    foo x;
    ...
    x = func();
    

Anmelden zum Antworten