Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Virtuelle Funktionen

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
23.02.2006, 12:58 Uhr
ref



sp->Draw() ; ( befindet sich in while(1) schleife ) , es ist klar hier wird nach der funktion
Draw() gesucht , und wenn diese funktion bei der basis klasse virtuell ist dann wird nach
der richtige Draw funktion gesucht bei den unteren klassen , wenn choice=3 dann sollte die Draw funktion bei der klasse Square gefunden werden , aber es gibt kein Draw funktion bei dieser
klasse , warum dann ist der Draw-funktion von Rectangle wieder ausgewählt??

ausgebe :

(1)Kreis (2)Rechteck (3)Quadrat (0)Beenden: 2
x x x x x x
x x x x x x
x x x x x x
x x x x x x

(1)Kreis (2)Rechteck (3)Quadrat (0)Beenden: 3
x x x x x
x x x x x
x x x x x
x x x x x
x x x x x

(1)Kreis (2)Rechteck (3)Quadrat (0)Beenden: 0



und hier ist der code :

C++:
// Listing 18.3. Shape-Klassen

#include <iostream>



class Shape

{

public:

     Shape(){}

     virtual ~Shape(){}

     virtual long GetArea() { return -1; } // Fehler

     virtual long GetPerim() { return -1; }

     virtual void Draw() {}

};



class Circle : public Shape

{

public:

     Circle(int radius):itsRadius(radius){}

     ~Circle(){}

     long GetArea() { return 3 * itsRadius * itsRadius; }

     long GetPerim() { return 9 * itsRadius; }

     void Draw();

private:

     int itsRadius;

     int itsCircumference;

};



void Circle::Draw()

{

     std::cout << "Routine zum Zeichnen eines Kreises an dieser Stelle!\n";

}





class Rectangle : public Shape

{

public:

     Rectangle(int len, int width):

         itsLength(len), itsWidth(width){}

     virtual ~Rectangle(){}

     virtual long GetArea() { return itsLength * itsWidth; }

     virtual long GetPerim() {return 2*itsLength + 2*itsWidth; }

     virtual int GetLength() { return itsLength; }

     virtual int GetWidth() { return itsWidth; }

     virtual void Draw();

private:

     int itsWidth;

     int itsLength;

};



void Rectangle::Draw()

{

     for (int i = 0; i<itsLength; i++)

     {

         for (int j = 0; j<itsWidth; j++)

             std::cout << "x ";



         std::cout << "\n";

     }

}



class Square : public Rectangle

{

public:

     Square(int len);

     Square(int len, int width);

     ~Square(){}

     long GetPerim() {return 4 * GetLength();}

};



Square::Square(int len):

     Rectangle(len,len)

{}



Square::Square(int len, int width):

     Rectangle(len,width)

{

     if (GetLength() != GetWidth())

         std::cout << "Fehler, kein Quadrat... ein Rechteck??\n";

}



int main()

{

     int choice;

     bool fQuit = false;

     Shape * sp;



     while (1)

     {

         std::cout << "(1)Kreis (2)Rechteck (3)Quadrat (0)Beenden: ";

         std::cin >> choice;



         switch (choice)

         {

         case 1:

             sp = new Circle(5);

             break;

         case 2:

              sp = new Rectangle(4,6);

             break;

         case 3:

             sp = new Square(5);

             break;

         default:

             fQuit = true;

             break;

         }

         if (fQuit)

             break;



         sp->Draw();

         std::cout << "\n";

     }

     return 0;

}




--
Man kann ein Problem nicht mit der gleichen Denkweise lösen, mit der es erschaffen wurde. (Albert Einstein)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
23.02.2006, 13:26 Uhr
ao

(Operator)



Zitat von ref:
warum dann ist der Draw-funktion von Rectangle wieder ausgewählt??

Weil alle Aufrufe von virtuellen Funktionen, die die Klasse selber nicht erfüllen kann, auf die Basisklassen umgeleitet werden.

Technisch wird das über eine Sprungtabelle realisiert, in der es für die Funktion void Draw (); genau einen Eintrag gibt. Wird ein Objekt vom Typ Square instanziert, dann tragen alle Klassen in ihrer Ableitungs-Reihenfolge ihre Draw-Funktion in die Tabelle ein: Erst kommt Shape, dann überschreibt Rectangle den Eintrag, und wenn Square eine eigene Draw-Funktion hätte, würde es diese dort als letztes eintragen. Hat es aber nicht, deshalb bleibt Rectangle::Draw stehen und wird beim Aufruf von Square.Draw angesprungen.

Das hier:

Zitat:

C++:
class Shape
{
public:
    virtual long GetPerim() { return -1; }
    virtual void Draw() {}
};



ist übrigens unüblich; man verwendet lieber "rein virtuelle" oder abstrakte Methoden:

C++:
class Shape
{
public:
    // Abstrakte Methoden
    virtual long GetPerim() = 0;
    virtual void Draw() = 0;
};


Damit wird klargemacht, dass Shape eine abstrakte Basisklasse ist, die nur zum Vererben der Schnittstelle dient. Konsequenzen:

1. Der Versuch, Shape direkt zu instanzieren

C++:
Shape * sh = new Shape ();

führt zum Compilerfehler.

2. Eine unvollständige Ableitung, die die abstrakten Methoden nicht überschreibt, führt auch zum Compilerfehler:

C++:
class Triangle : public Shape
{
// Überschreiben von GetPerim und Draw vergessen
};

Triangle tri = new Triangle (); // Compilerfehler



ao

Dieser Post wurde am 23.02.2006 um 13:27 Uhr von ao editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: