Generische Vektoren
Kurzes Beispiel für Vektoren im kartesischen Raum.
template<size_t N = 3, typename T = double>
class Point
Ohne Spezifizierung haben wir einen Punkt Point<> p
im Raum vom doppeltgenauen Gleitkomma-Typ.
Wir benutzen using Point3D = Point<>
und können daher einfach Point3D p
schreiben.
Weiterhin benutzen wir using Point2DInt = Point<2, int>
für diskrete Punkte in der Ebene.
Konstruktor
Wir haben den KonstruktorPoint(initializer_list<T>)
und können damit Vektoren so definieren: Point3D p {1.2, -5.3, 10};
.
Falls die Initialisierungsliste zu kurz oder zu lang ist, wird mit 0 aufgefüllt bzw. werden überflüssige Werte abgeschnitten.
Weiterhin haben wir Point() = default
gesetzt. Damit definiert
Point3D p;
einen Vektor mit undefinierten Koordinaten und Point3D p {};
den Ursprung. (Das verhält sich analog zu dem Standardverhalten in C++: bei int i;
ist i
undefiniert und bei int i {};
ist i == 0
.)
Die Koordinaten werden intern in der privaten Membervariablen T array[N]
gespeichert. (Es ist nicht nötig, die Felder dynamisch mit new
zu erzeugen, da N
zur Übersetzungszeit bekannt ist.
Damit brauchen wir keinen Destruktor, Kopier-/Verschiebe-Konstruktoren und -Zuweisungen zu definieren.)
Operationen
Das Tolle an C++ ist, dass man Operatoren überladen kann. Damit können wir mit den Vektoren wie mit integrierten Datentypen umgehen.Ausgabe
Wir können die Vektoren ausgeben.cout << "p: " << p << endl;
schreibt
p: [1.2, -5.3, 10]auf die Konsole.
Punktspiegelung im Ursprung
Das istPoint3D p2 = -p
;
Verschieben
Point3D p1, p2, p3 = irgendwas;
p3 += {1, 2, 3};
p3 = p1 + p2;
p3 -= p2;
p3 = Point3D{5, 6, 7} - p1;
Vergleichen
Point2DInt p1, p2 = irgendwas;//int lässt sich besser als double vergleichen
cout << boolalpha << (p1 == p2) << ' ' << (p1 != p2);
Skalieren
cout << 0.5*p;
Skalarprodukt
cout << "Laenge: " << sqrt(p*p);
Zugriff auf ein einzelnes Element
cout << p[1] << endl;
p[0] = 15;
Hier findet keine Bereichsüberprüfung statt analog zum []
-Zugriff bei integrierten Arrays oder beim vector
.
C++ traut dem Entwickler zu, den richtigen Index zu setzen, und liefert dafür eine bessere Performance.
Download
Quellcode
Hier befinden sich die Qt Projektdatei und der C++ Quellcode.
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += main.cpp
HEADERS += \
point.h
CONFIG += c++11
#include <iostream>
#include <cmath>
#include "point.h"
using namespace std;
void test2D() {
Point2DInt p2_1;
Point2DInt p2_2 {1.3, -5};//Hier Compiler-Warnung
cout << "p2_1" << p2_1 << endl;
cout << "p2_2" << p2_2 << endl;
cout << boolalpha << (p2_1 == p2_2) << endl;
p2_1 -= p2_1;
p2_1 += {1, -5};
cout << (p2_1 == p2_2) << endl;
cout << (p2_1 != p2_2) << endl;
cout << (p2_1 == p2_1) << endl;
cout << 2*p2_1 << endl;
cout << "length: " << sqrt(p2_1*p2_1) << endl;
}
void test3D() {
Point<> p3_1;
Point3D p3_2 {};
Point3D p3_3 {1.2, -5.3, 10};
Point3D p3_4 {-5.};
Point3D p3_5 = -p3_3;
cout << "p3_1 " << p3_1 << endl;
cout << "p3_2 " << p3_2 << endl;
cout << "p3_3 " << p3_3 << endl;
cout << "p3_4 " << p3_4 << endl;
cout << "p3_5 " << p3_5 << endl;
cout << "-p3_5 " << -p3_5 << endl;
p3_1 = {};
p3_1 += {1.5, 2, 3};
cout << "p3_1 " << p3_1 << endl;
p3_1 += p3_4;
cout << "p3_1 " << p3_1 << endl;
p3_1 -= {3, -0.5};
cout << "p3_1 " << p3_1 << endl;
p3_1 = p3_3 + p3_4;
cout << "p3_1 " << p3_1 << endl;
p3_1 = Point3D{5, 6, 7} + p3_1;
cout << "p3_1 " << p3_1 << endl;
p3_1 = p3_1 - p3_1;
cout << "p3_1 " << p3_1 << endl;
cout << p3_3[1] << endl;
p3_3[2] = -10.3;
cout << "p3_3 " << p3_3 << endl;
}
int main()
{
test2D();
test3D();
return 0;
}
#ifndef POINT_H
#define POINT_H
#include <initializer_list>
#include <ostream>
using namespace std;
template<size_t N = 3, typename T = double>
class Point
{
T array[N];
public:
Point() = default;
Point(initializer_list<T> values) {
for (size_t i {0}; i != values.size() && i != N; ++i)
array[i] = values.begin()[i];
for (size_t i {values.size()}; i != N; ++i)
array[i] = 0;
}
friend ostream& operator<<(ostream& os, const Point<N,T>& point) {
os << "[";
for (size_t i {0}; i != N; ++i) {
os << point.array[i];
if (i != N - 1)
os << ", ";
}
os << "]";
return os;
}
Point operator-() const {
Point p;
for (size_t i {0}; i != N; ++i)
p.array[i] = -array[i];
return p;
}
Point operator+=(const Point& other) {
for (size_t i {0}; i != N; ++i)
array[i] += other.array[i];
return *this;
}
Point& operator-=(const Point& other) {
*this+=(-other);
return *this;
}
bool operator==(const Point& other) {
if (this == &other)
return true;
for (size_t i {0}; i != N; ++i)
if (array[i] != other.array[i])
return false;
return true;
}
bool operator!=(const Point& other) {
return !(*this == other);
}
friend Point operator*(double s, const Point& point) {
Point q;
for (size_t i {0}; i != N; ++i)
q.array[i] = s*point.array[i];
return q;
}
friend T operator*(const Point& a, const Point& b) {
T res {0};
for (size_t i {0}; i != N; ++i)
res += a.array[i]*b.array[i];
return res;
}
T& operator[](size_t i) {
return array[i];
}
const T& operator[](size_t i) const {
return array[i];
}
};
template<size_t N, typename T>
Point<N, T> operator+(const Point<N, T>& a, const Point<N, T>& b) {
Point<N, T> p {a};
p += b;
return p;
}
template<size_t N, typename T>
Point<N, T> operator-(const Point<N, T>& a, const Point<N, T>& b) {
return a + (-b);
}
using Point3D = Point<>;
using Point2DInt = Point<2, int>;
#endif // POINT_H