Problem mit Überladen von operator()



  • Hallo, ich bin C++-Anfänger.

    Ich habe eine Klasse Array3D mit Zugriffsoperator:

    class Array3D
    { ...
    private:
    	T ***mat; //das eigentl. gekapselte dynamische 3D-Array
    	unsigned int length1, length2, length3; //die 3 Dimensionen
    };
    
    //! Initialisiert das dreidimensionale Array.
    template<class T>
    void Array3D<T>::init(unsigned int length1, unsigned int length2, unsigned int length3, T value) {
    	this->length1 = length1;
    	this->length2 = length2;
    	this->length3 = length3;
    	mat = new T** [length2]; 
    	for (unsigned int i = 0; i < length2; i++) {
    		mat[i] = new T* [length1];
    		for (unsigned int j = 0; j < length1; j++) {
    			mat[i][j] = new T [length3];
    		}
    	}
    	for (unsigned int i = 0; i < length3; i++) {
    		for (unsigned int j = 0; j < length2; j++) {
    			for (unsigned int k = 0; k < length1; k++) {
    				mat[j][i][k] = value; 
    			}
    		}
    	}
    }
    
    //! ()-Zugriffs-Operator fuer das gekapselte dynamische dreidimensionale Array mat fuer non-const - Array3D-Objekt. 
    template<class T>
    T& Array3D<T>::operator() (unsigned int x, unsigned int y, unsigned int z) {
    	assert(x <= length1 && y <= length2 && z <= length3);
    	return mat[y][x][z];
    }
    
    //! ()-Zugriffs-Operator fuer das gekapselte dynamische dreidimensionale Array mat fuer const - Array3D-Objekt. 
    template<class T>
    T Array3D<T>::operator() (unsigned int x, unsigned int y, unsigned int z) const {
    	assert(x <= length1 && y <= length2 && z <= length3);
    	return mat[y][x][z];
    ...
    }
    

    und einen Filter, ebenfalls mit Zugriffsoperator, der den Operator von Array3D verwendet.

    class Filter
    {
    protected:
    	Array3D<unsigned int> mat;
    ...
    unsigned int& Filter::operator() (unsigned int x, unsigned int y, unsigned int z) {
    	return mat(x, y, z);
    }
    
    unsigned int Filter::operator() (unsigned int x, unsigned int y, unsigned int z) const {
    	return mat(x, y, z);
    }
    

    Wenn ich nun:

    Filter *f = new Gauss_Filter(3);
    cout << f->operator ()(1, 1, 1);
    

    dann bekomme ich eine Zugriffsverletzung beim Lesen an Position...

    Kann mir jmd. helfen 😕



  • Das ist kein 3D-Array, das ist eine Art Listen von Listen von Listen oder so. Ein 3D-Array sieht so aus: vector<T> v(l1 * l2 * l3), die Indexe darfst du dann selbst berechnen. Das ist nicht nur wesentlich effizienter, sondern macht die ganzen "Algorithmen" auch noch nahezu trivial.



  • Bevor du da den Fehler suchst, solltest du die Funktion noch einmal überarbeiten.

    Es ist in diesem Fall Schwachsinn, Pointer auf Pointer auf Pointer zu haben. Stattdessen solltest du die Elemente sinnvoll anordnen und als ganzen Block im Speicher haben.
    Du brauchst insgesamt ein Array der Größe length1*length2*length3
    Darauf greifst du zu, indem du den Index berechnest durch ((z*length2)+y)*length1+x
    Dann kannst du die Daten auch einfach in std::vector kapseln und sparst dir den unsicheren Umgang mit new[] und delete[].
    Statt assertions solltest du lieber Exceptions verwenden.

    Dann sehe ich nicht ein, warum du den Gaussfilter mit new erzeugst, das wird dann nämlich viel übersichtlicher, schneller und sicherer:

    Gauss_Filter f(3);
    cout << f(1, 1, 1);
    

    Die Operatoren haben doch gegenüber Funktionen den Vorteil, dass man sie einfacher und intuitiver verwenden kann, also in dem Beispiel hier ein Objekt wie eine Funktion aufrufen kann.



  • assert(x <= length1 && y <= length2 && z <= length3);
    

    Statt "kleiner gleich" muss es hier "kleiner" heissen.
    So wie Du es bei der Initialisierung in den for-Schleifen richtig hast.

    Denk dran, dass bei 0 angefangen wird zu nummerieren:

    Filter *f = new Gauss_Filter(3);
    cout << f->operator ()(1, 1, 1); // das interne array ist min. [2][2][2]?
    


  • Statt "kleiner gleich" muss es hier "kleiner" heissen.

    Danke Dir, hatte schon einige Probleme damit, die ich nicht gesehen habe...

    cout << f->operator ()(1, 1, 1); // das interne array ist min. [2][2][2]?

    Ja, new Gauss_Filter(3) legt ein ein "Array" der Größe [3][3][3] an.

    Dann kannst du die Daten auch einfach in std::vector kapseln

    Werde ich versuchen...

    Die Sache ist, dass

    Array3D<double>* mat = new Array3D<double>(3, 3, 3, 0.0);
    cout << mat->operator ()(1, 1, 1) << endl;
    

    funktioniert und

    Filter *f = new Gauss_Filter(3);
    cout << f->operator ()(1, 1, 1);
    

    und

    Gauss_Filter *fg = new Gauss_Filter(3);
    cout << fg;
    cout << fg->operator ()(1, 1, 1) << endl;
    

    nicht...

    Ich würde gerne folgendes machen...
    Filter ist die "Oberklasse", Gauss_Filter und Homogen_Filter Unterklassen:

    Filter* f = new Gauss_Filter(3);
    cout << f;
    f->setMask(5);
    cout << f;
    f = new Homogen_Filter(3);
    cout << f;
    f->setMask(7);
    cout << f;
    

    also zwischen den Filtern hin und her wechseln...
    und darauf zugreifen mittels operator()

    btw: << habe ich ebenfalls überladen und das funktioniert...


Log in to reply