class MyLVector { private: // coordinates, hidden double t; double x; double y; double z; public: MyLVector();// The default constructor MyLVector(double c0, double c1, double c2, double c3);// Other constructor // methods: double Length() const; // get length of vector double T() const; double X() const; double Y() const; double Z() const; MyLVector Add( const MyLVector & p ) const; // add two vectors double Angle( const MyLVector & p ) const; // angle between two vectors double Mass() const; // get mass of 4-vector };
Vierer-Vektor kann als Erweiterung des Dreier-Vektor angesehen werden. Viele Gemeinsamkeiten mit Dreier-Vector und ein paar Erweiterungen
Design Prinzip Code-Reuse statt cut&paste !
class MyLVector { private: // coordinates, hidden double t; My3Vector vec3; // My3Vector as private member public: MyLVector();// The default constructor MyLVector(double c0, double c1, double c2, double c3);// Other constructor // methods: double Length() const; // get length of vector double T() const; double X() const; double Y() const; double Z() const; MyLVector Add( const MyLVector & p ) const; // add two vectors double Angle( const MyLVector & p ) const; // angle between two vectors // .... };
LorentzVektor enthält DreierVektor:
"has-a" relationship
(Aggregation).
// implementation // Constructor MyLVector::MyLVector(double c0, double c1, double c2, double c3) : vec3(c1, c2, c3), t(c0) // special initialization syntax {} double MyLVector::Angle( const MyLVector & p ) const { return( vec3.Angle(p.vec3)); // re-use code } double MyLVector::X() const { return( vec3.X() ); // re-use code }
Im Prinzip ok, allerdings viele stumpfsinnige Mapping-Funktionen von DreierVektor auf ViererVektor nötig.
3. Möglichkeit: Vererbung
ViererVektor ist DreierVektor mit ein paar Ergänzungen ....
#include "My3Vector.h" // My3Vector declarations class MyLVector : public My3Vector { // inherit from My3Vector private: double t; public: MyLVector();// The default constructor MyLVector(double c0, double c1, double c2, double c3);// Other constructor // methods: double Mass() const; // get mass of 4-vector double Mass(const MyLVector & p) const; // get mass of two 4-vector }; // implementation MyLVector::MyLVector(double c0, double c1, double c2, double c3) : My3Vector(c1, c2, c3), t(c0) // special initialization syntax {} double MyLVector::Mass() const // Method for mass: { return( sqrt( t*t - x*x - y*y - z*z ) ); }
Falls Methode geändert werden muss, z.B. MyLVector::Add, entsprechend neu implementieren, bei c.Add(d) wird dann die MyLVector Version benutzt.
Vererbung ( "is-a" relationship) bedeutet alle Eigenschaften und Funktionen einer Grund-Klasse ( base class) in eine weitere Klasse ( derived class) zu übernehmen. Daraus ergibt sich eine enorme Erweiterung der Funktionalität. Ausgehend von vorhandenen, simplen Grundklassen können relativ leicht neue Klassen abgeleitet werden, ohne jedesmal diesselben grundlegenden Funktionen neu zu implementieren.
Allerdings: Vererbung nicht übertreiben, nicht immer sinnvoll.
class Rechteck { // ... void setLength( double); void setWidth( double); // ... double length, width; };
Was soll ein Quadrat mit diesen Funktionen machen ?
setLength(..) bei Quadrat ändert immer auch width und vice-versa. Verhalten nicht kompatibel mit Rechteck .
Wichtig für OO Programmieren ist konsistentes Verhalten von Klassen, dazu wird Vererbung eingesetzt. Es geht weniger um bequemes Übernehmen von Funktionalität.
Mathematisch ist Quadrat Unterklasse von Rechteck, aber nicht im Sinne von OOP !
Abhilfe: Weiterer Modifier protected, im Prinzip analog zu private, d.h. kein Zugriff von ausserhalb der Klasse, jedoch mit Ausnahme von abgeleiteten Klassen.