Mechanismus für Virtuelle Methodenaufrufe umgehen.

Thomas Darimont

Erfahrenes Mitglied
Hallo!

Wie kann man den bei virtuellen Methoden den Mechanismus zum virtuellen Funktionsaufruf umgehen?

Beispiel:

Code:
#include <iostream>
#include <cmath>

using namespace std;

static double PI = acos(-1);

class Figur{

	int xPos;
	int yPos;

public:
	Figur(int x, int y){
		this->xPos = x;
		this->yPos = y;
	};
	virtual ~Figur(){};
	virtual double berechneFlaeche() = 0;

};

class Kreis : public Figur{
	double radius;
public:
	Kreis(int x, int y, double r):Figur(x,y),radius(r){};
	~Kreis(){};
	double berechneFlaeche(){return this->radius * this->radius * PI;};
};


class Rechteck : public Figur {
protected:
	double seiteA;
	double seiteB;
public:
	Rechteck(int x, int y, double a, double b): Figur(x,y), seiteA(a), seiteB(b){};
	virtual ~Rechteck(){};
	virtual double berechneFlaeche(){ return this->seiteA * this->seiteB;};
};

class Quadrat : public Rechteck {
public:
	Quadrat(int x, int y, double a) : Rechteck(x,y,a,a){};
	~Quadrat(){};
	virtual double berechneFlaeche(){ return this->seiteA * this->seiteA;};
};


int main(int argc, char *argv[]){

	//Hier wird ja jeweils ein Lookup in die VTabele (Virtuelle Funktionen Tabelle) gemacht
	//und die passende Methode zur jeweiligen instanz besorgt...
	Figur* f = new Kreis(10,100,152);
	cout << f->berechneFlaeche() << endl;
	
	//...
	Figur* f1 = new Rechteck(1,2,100.0,231.0);
	cout << f1->berechneFlaeche() << endl;

	//...
	Figur* f2 = new Quadrat(100,100,256.0);
	cout << f2->berechneFlaeche() << endl;

	//Ich habe nun im Buch "Die C++ Programmiersprache von Bjarne Stroustrup im Kapitel 
	//Abgeleitete Klassen davon gelesen, dass man den VTable Lookup umgehen kann indem man mittels
	//des "Scope Resultions Operators" :: der Methode berechneFlaeche() schon den richtigen "scope"
	//mitgibt.
	//Wie mache ich das OHNE f3 als Quadrat oder Quadrat definieren zu müssen?
	

	Figur* f3 = new Quadrat(12,123,1233.0);
	//cout << Quadrat::f3::berechneFlaeche() <<endl; <- das Funktioniert nicht...

	delete f;
	delete f1;
	delete f2;

	return 0;
}

Gruß Tom
 
Hi,

wenn ich dich richtig verstanden hab, sollte es das folgende tun:

Code:
        Figur* f3 = new Quadrat(12,123,1233.0);
        cout << ((Quadrat*)f3)->Rechteck::berechneFlaeche() <<endl; //<- das Funktioniert

Wobei man sagen muss das Downcasts immer nicht gern gesehen werden, und
es in C++ keinen Operator für das Abfragen eines Types gibt sollte folgender
Trick den Downcast sicher machen:


Code:
#include <iostream>
#include <math.h>

using namespace std;

static double PI = acos((double)-1);

class Quadrat;
class Kreis;
class Rechteck;     

class Figur{

        int xPos;
        int yPos;

public:
        Figur(int x, int y){
                this->xPos = x;
                this->yPos = y;
        };
        virtual ~Figur(){};
        virtual double berechneFlaeche() = 0;
        virtual Rechteck* castToRechteck(){ return 0; }
        virtual Quadrat* castToQuadrat(){ return 0; }
        virtual Kreis* castToKreis(){ return 0; }
};

class Kreis : public Figur{
        double radius;
public:
        Kreis(int x, int y, double r):Figur(x,y),radius(r){};
        ~Kreis(){};
        double berechneFlaeche(){return this->radius * this->radius * PI;}; 
        Kreis* castToKreis(){ return this; }
        
};


class Rechteck : public Figur {
protected:
        double seiteA;
        double seiteB;       
public:
        Rechteck(int x, int y, double a, double b): Figur(x,y), seiteA(a), seiteB(b){};
        virtual ~Rechteck(){};
        virtual double berechneFlaeche(){ return 5;}
        Rechteck* castToRechteck(){ return this; }
        
};

class Quadrat : public Rechteck {
public:
        Quadrat(int x, int y, double a) : Rechteck(x,y,a,a){}; 
        ~Quadrat(){};        
        virtual double berechneFlaeche(){ return this->seiteA * this->seiteA;}
        Quadrat* castToQuadrat(){ cout << "Bin drin" << endl;return this; }
};


int main(int argc, char *argv[]){ 

        //Hier wird ja jeweils ein Lookup in die VTabele (Virtuelle Funktionen Tabelle) gemacht
        //und die passende Methode zur jeweiligen instanz besorgt...
        Figur* f = new Kreis(10,100,152);
        cout << f->berechneFlaeche() << endl;

        //...
        Figur* f1 = new Rechteck(1,2,100.0,231.0);
        cout << f1->berechneFlaeche() << endl;

        //...
        Figur* f2 = new Quadrat(100,100,256.0);
        cout << f2->berechneFlaeche() << endl;

        //Ich habe nun im Buch "Die C++ Programmiersprache von Bjarne Stroustrup im Kapitel 
        //Abgeleitete Klassen davon gelesen, dass man den VTable Lookup umgehen kann indem man mittels
        //des "Scope Resultions Operators" :: der Methode berechneFlaeche() schon den richtigen "scope"
        //mitgibt.
        //Wie mache ich das OHNE f3 als Quadrat oder Quadrat definieren zu müssen?


        Figur* f3 = new Quadrat(12,123,1233.0);
        if(f3->castToQuadrat())
                cout << f3->castToQuadrat()->Rechteck::berechneFlaeche() <<endl; //<- das Funktioniert 

        delete f;
        delete f1;
        delete f2;

        return 0;
}

Gruß

RedWing
 
Zuletzt bearbeitet:
Hallo!

Erstmal vielen Dank für deine Lösung.:)
Jedoch finde ich etwas ungeschickt in der Basisklasse Figur ALLE Subtypen casts festzulegen. Gibt es da nicht noch eine andere Möglichkeit (ebenfalls OHNE Cast)

Btw. ist ein Cast von einem Bastype auf einen Subtyp nicht ein Up-Cast?;-)

Gruß Tom
 
Hi,
Tom hat gesagt.:
Jedoch finde ich etwas ungeschickt in der Basisklasse Figur ALLE Subtypen casts festzulegen. Gibt es da nicht noch eine andere Möglichkeit (ebenfalls OHNE Cast)

Eine andre Möglichkeit sehe ich in deinem Beispiel nicht, da du ja den virtuellen
Methodenaufruf umgehen willst, und somit dem Compiler irgendwie (statisch) sagen
musst, wo deine Methode liegt die du gerne Aufrufen würdest,
allerding gibt es eine elegantere Lösung wie die meine, nämlich mit Hile
des dynamic_cast<T> opertors:

Code:
        if(dynamic_cast<Quadrat*>(f3))
                cout << dynamic_cast<Quadrat*>(f3)->Rechteck::berechneFlaeche() <<endl; //<- das Funktioniert
Schau dir auch mal dieses Tutorial zum Thema dynamic_cast an...

Meine Lösung war aus Scott Meyer's "Effektiv C++" und das war ne ältere
Ausgabe....

Btw. ist ein Cast von einem Bastype auf einen Subtyp nicht ein Up-Cast?

Also das ich glaube ich ist Defnitionssache, für mich ist es ein downcast entlang der
Klassenhierearchie, aber ich lass mich gern belehren ;)

Gruß

RedWing
 
Zurück