Vektorenaddition
-
zu dir Caipi, ja ich habe eine eigene Class vector im eigenst dafür erstellten namespace BaseVector liegen. Von der C++ Typischen Klasse Vector darf ich nicht erben. Ich soll mir selbst Funktionen dafür überlegen. Es handelt sich hierbei wieder um eine sinnlose Beschäftigungstherapie unseres Dozenten, die einein nur davon abhält für andere Vorlesungen zu pauken.
Um einen Detailreichen überblick über die Aufgaben zu geben:Aufgabe
Gegeben ist das folgende Programm:
#include <iostream>
#include "vector.h"
using namespace std;
using namespace BaseVector;
int main(){
Vector v1(3,2.0),v2(3,3.0);
Vector v3 = v1.addElements(v2);
cout << v3 << endl;
Vector v4 = v1.multiplyElements(v2);
cout << v4 << endl;
v1.setElement(0,0.5);
v2.setElement(2,0.5);
double d = v1.scalarProduct(v2);
cout << d << endl;
cout << v1.n() << endl;
cout << v1.getElement(0) << endl;
v1 = v2;
return 0;
}
Implementierten Sie alle erforderlichen Klassen, Operatoren und Funktionen, damit das obenstehende
Programm fehlerfrei kompiliert und ausgeführt werden kann.
Wenn Sie alles richtig implementiert haben, erzeugt das Programm bei seiner Ausführung folgende
Ausgabe:
Vector(5,5,5)
Vector(6,6,6)
8.5
3 0.5
Bitte beachten Sie folgende Hinweise:
• Teilen Sie den von Ihnen implementierten Code in eine Header- und eine Implementierungsdatei auf .
• Die Memberfunktionen der von Ihnen implementierten Klassen sollen alle über späte Bindung verfügen.
• addElements() addiert die Werte zweier Vektoren elementweise und gibt das Ergebnis als neuen Vektor zurück.
• multiplyELements() multipliziert die Werte zweier Vektoren elementweise und gibt das Ergebnis als neuen Vektor zurück.
• scalarProduct() berechnet das Skalarprodukt zweier Vektoren und gibt es als double-Wert zurück.
• Verwenden Sie weder in der von Ihnen erstellten Headerdatei noch in der Implementierungsdatei die Anweisung "using namespace std;". Greifen Sie vielmehr ausschließlich vollständig qualifiziert auf Bezeichner des Namensraums std zu.
-
für jemanden der reine Informatik studiert oder wer sich anderweitig langweilt und deswegen ausschließlich in C++ übt, eine sicherlich leichte Aufgabe. Leider studiere ich Wirtschaftsinformatik und die Vorlesungen in Programmierung werden mir zunehmend unverständlicher und Kryptischer. Ich bin euch daher für eure Hilfe sehr dankbar.
Und kurze Anmerkung: Was versteht ihr unter tags?
-
Zu den Tags: http://www.c-plusplus.net/forum/viewtopic-var-t-is-59601.html
Ansonsten: Zeig uns doch mal deine bisherige _komplette_ Klasse. (In Codetags)Caipi
-
die main in der Aufgabestellugen kennst du ja,
hier die Header Datei:#include <iostream> namespace BaseVector{ class Vector{ public: Vector(); Vector(int n, double wert); ~Vector(); virtual const double& getElement(unsigned int i) const; virtual void setElement(unsigned int i, const double value); virtual const int& n(); virtual int groesse() const; virtual void ausgeben(std::ostream& os) const; virtual Vector addElements(const Vector &vReference); virtual Vector multiplyElements(const Vector &vReference); virtual double scalarProduct(const Vector &vReference); private: int n_; double wert_; double * elemente_; }; std::ostream& operator <<(std::ostream& os, const Vector& outVec); } #endif //VECTOR_Hund hier die der Inhalt der cpp:
#include "vector.h" namespace BaseVector{ Vector::Vector():elemente_(NULL),n_(NULL),wert_(NULL){}; Vector::Vector(int n,double wert):elemente_(NULL),n_(n),wert_(wert) { elemente_ = new double[groesse()]; for(int i=0;i<n_;++i){ elemente_[i]=wert_; } }; Vector::~Vector() { delete[] elemente_; }; const double& Vector::getElement(unsigned int i) const { return elemente_[i]; } void Vector::setElement(unsigned int i, const double value) { elemente_[i] = value; } const int& Vector::n(){ return n_; } Vector Vector::addElements(const Vector &vReference){ Vector temp(3,0.0); for(int i=0;i<vReference.n_;++i) temp.setElement(i, getElement(i)+vReference.getElement(i)); return temp; } Vector Vector::multiplyElements(const Vector &vReference){ Vector temp(3,0.0); for(int i=0;i<vReference.n_;++i) temp.setElement(i, getElement(i)*vReference.getElement(i)); return temp; } double Vector::scalarProduct(const Vector &vReference){ double value = 0.0; for(int i=0;i<vReference.n_;++i) value += getElement(i)*vReference.getElement(i); return value; } void Vector::ausgeben(std::ostream& os) const { os << elemente_[0] << ',' << elemente_[1] << ',' << elemente_[2]; } int Vector::groesse() const { return n_; }; std::ostream& operator<<(std::ostream& os, const Vector& outVec){ std::ostream::sentry VorUndNacharbeiten(os); if(VorUndNacharbeiten) outVec.ausgeben(os); return os; } }
-
Hier stand Quark.
Caipi
-
ich wurde grad drauf hingewiesen, dass mir der Kopierkonstruktor fehlt und ich somit die KOF nicht eingehalten habe, was den Fehler verursacht. Ich werde ihn mal noch einpflegen und dann schau ich mal weiter

trotzdem danke für eure Postings, jetzt weiß ich wenigstens schon mal wie ich tagger
Freue mich trotzdem über jede antwort, die mir hilft den Code sicherer zu gestallten. Wenn sich jemand mit asserts und ihrer Verwendung auskennt, dann immer her mit dem Imput. Ich stell mir jetzt noch ne Puddl Cachacha an den Tisch und dann kann der Abend beginnen.
-
nein, leider erzeugt das addieren und multiplizieren müll in der Rückgabe, weil es wie gesagt den Speicher per Destruktoraufruf frei gibt. Was benutzt du für einen Compiler? Vielleicht erklärt das auch, dass er bei dir durchläuft.
Great thanxxx for answers
Curry
-
curry schrieb:
nein, leider erzeugt das addieren und multiplizieren müll in der Rückgabe, weil es wie gesagt den Speicher per Destruktoraufruf frei gibt. Was benutzt du für einen Compiler? Vielleicht erklärt das auch, dass er bei dir durchläuft.
Great thanxxx for answers
Curryg++. Aber wie du bereits selbst geschrieben hast, fehlt der Copy-Ctor. Dieser sollte etwa so aussehen:
Vector::Vector(const Vector& vec) { n_ = vec.n_ elemente_ = new double[n_]; for(unsigned int i = 0; i < n_; ++i) elemente_[i] = vec.elemente_[i]; }Caipi
-
Vector::Vector(const Vector& copyVector):elemente_(NULL),n_(copyVector.groesse()){ elemente_ = new double[groesse()]; for (int i = 0; i < groesse(); ++i) elemente_[i] = copyVector.elemente_[i]; };das hier hatte mir noch gefehlt Caipi, jetzt funzts.
Jetzt kann ich auch befriedigt ins Bett gehen. Noch eine kurze Frage an dich: Was studerst du und hast du ICQ? Für den Fall, dass man mal noch andere Fragen haben sollge.
-
curry schrieb:
Vector::Vector(const Vector& copyVector):elemente_(NULL),n_(copyVector.groesse()){ elemente_ = new double[groesse()]; for (int i = 0; i < groesse(); ++i) elemente_[i] = copyVector.elemente_[i]; };So in der Art wie ich geschrieben hab ;). Trotzdem eine Frage dazu: Warum setzt du den Zeiger elemente_ auf Null, wenn du ihm direkt danach eine Adresse zuweist?
das hier hatte mir noch gefehlt Caipi, jetzt funzts.
Jetzt kann ich auch befriedigt ins Bett gehen. Noch eine kurze Frage an dich: Was studerst du und hast du ICQ? Für den Fall, dass man mal noch andere Fragen haben sollge.Ich studiere garnichts. Gehe in die Schule... Desweiteren kannst du doch deine Fragen hier stellen, oder?

Caipi
-
ich setze ihn aus dem Grund auf NULL, weil stell dir vor dein Programm kommt aus irgend einer fehlerhaften Implementierung ins Rudern und eine Elementzuweisung kommt nicht mehr zustande, wo greift der Destruktort dann hin? Ins Leere, richtig, und dass was er dabei an Daten versehentlich löschen kann, kann zu schweren Fehlern führen.
-
das mit dem Fragen hier stellen, ist immer so eine lässtige angelegenheit mit dem warten auf Antworten. Einige der hier anwesenden halten sich gerne für Überflieger und Posten dementsprechend völlig unzureichende überhebliche Antworten. Daher ist mir's lieb einen Stamm an C++ Usern zu Adden auf den man verlässlich in Problemsituaionen zurückgreifen kann.
Deswegen der ausweg ins ICQ
-
curry schrieb:
ich setze ihn aus dem Grund auf NULL, weil stell dir vor dein Programm kommt aus irgend einer fehlerhaften Implementierung ins Rudern und eine Elementzuweisung kommt nicht mehr zustande, wo greift der Destruktort dann hin?
Wo greift der Dtor denn jetzt hin?

Ins Leere, richtig,
So auch jetzt.
und dass was er dabei an Daten versehentlich löschen kann, kann zu schweren Fehlern führen.
Stimmt.
Es ist nicht so, dass wenn du einem Zeiger 0 setzt, nichts mehr schief gehen kann. Im Gegenteil. Wenn du einen Zeiger, der auf 0 zeigt, dereferenzierst, gibt es ziemlich sicher einen Crash, da 0 nie eine gültige Adresse repräsentiert.
Warum setzt man nun aber den Zeiger gleich 0? Das tut man deswegen, da man vor dem dereferenzieren oder freigeben überprüft ob dieser gleich 0 ist, und sofern diese Bedingung zutrifft man den Speicher _nicht_ dereferenziert oder freigibt...Caipi
-
na das klingt doch auch nicht schlecht
wieder was gelernt.
Dann mach dir mal noch nen schönen Abend. Wenn du lust hast dich noch bisschen mehr über C++ Relevante Sachen auszutauschen hier meine ICQ addi: 70049002
in diesem Sinne: N8Gruß Curry
-
● Der Standardkonstruktor beschafft und initialisiert dynamische
Anteile
● Handelt es sich um dynamischen Speicher wird der entsprechende
Zeiger in der Initialisiererliste mit NULL initialisiert
● Der nötige Speicher wird im Konstruktor mit new oder new[] beschafft
● Schlägt die Speicherbeschaffung fehl, enthält der Zeiger den Wert NULL
● Ein anschließender Destruktoraufruf, der den Zeiger mit delete
oder delete [] freigibt, bleibt dann ohne negative Folgen
● Ein NULL-Zeiger darf beliebig oft freigegeben werden
● Dynamischen Speicher keinesfalls in der Initialisiererliste beschaffen!
● Im Falle eines Fehlschlags hätte der Zeiger einen Wert ungleich NULL
● Ein späterer Destruktoraufruf mit delete oder delete[] hätte dann
negative FolgenSo stands im Skriptum, man darf demzufolge einen solchen Zeiger dereferenzieren.
Gruß Curry
-
curry schrieb:
● Schlägt die Speicherbeschaffung fehl, enthält der Zeiger den Wert NULL
Diese Info ist veraltet.
Nach aktuellem C++ Standard wird dem Zeiger nicht der Wert 0 zugewiesen sondern eine Exception geworfen...So stands im Skriptum, man darf demzufolge einen solchen Zeiger dereferenzieren.
Dereferenzieren nicht, wenn überhaupt freigeben...
Vergl.#include <iostream> using namespace std; int main() { int* p = 0; cout << *p << endl; }(oder hab ich was überlesen?).
Jedoch würde mich das mit dem "auf einen Null-Zeiger darf beliebig oft delete angewendet werden" auch mal interessieren. Ist das nach aktuellem Stadard legal?
Ich habe nämlich dumpf in Erinnerung, dass man nur Speicher der mit new erzeugt wurde wieder freigeben darf und wenn nach aktuellem Standard bei einem Fehlschlag von new der Zeiger nicht gleich null gesetzt wird, dann ist ein Null-Zeiger ja nicht mit new erzeugt, oder? (Sorry, bin Noob :))
Kann mich da jemand aufklären? :).Caipi
-
5.3.5 Delete [expr.delete]
1 The delete-expression operator destroys a most derived object (1.8) or array created by a new-expression.
delete-expression:
::opt delete cast-expression
The first alternative is for non-array objects, and the second is for arrays. The operand shall have a pointer
type, or a class type having a single conversion function (12.3.2) to a pointer type. The result has type
void.
2 If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned
conversion function, and the converted operand is used in place of the original operand for the remainder of
this section. In either alternative, if the value of the operand of delete is the null pointer the operation
has no effect. In the first alternative (delete object), the value of the operand of delete shall be a pointer
to a non-array object or a pointer to a sub-object (1.8) representing a base class of such an object (clause
10). If not, the behavior is undefined. In the second alternative (delete array), the value of the operand of
delete shall be the pointer value which resulted from a previous array new-expression.72) If not, the
behavior is undefined. [Note: this means that the syntax of the delete-expression must match the type of the
object allocated by new, not the syntax of the new-expression. ] [Note: a pointer to a const type can be
the operand of a delete-expression; it is not necessary to cast away the constness (5.2.11) of the pointer
expression before it is used as the operand of the delete-expression. ]
3 In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the
static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual
destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the
object to be deleted differs from its static type, the behavior is undefined.73)
4 The cast-expression in a delete-expression shall be evaluated exactly once. If the delete-expression calls
the implementation deallocation function (3.7.3.2), and if the operand of the delete expression is not the
null pointer constant, the deallocation function will deallocate the storage referenced by the pointer thus
rendering the pointer invalid. [Note: the value of a pointer that refers to deallocated storage is indeterminate.]
5 If the object being deleted has incomplete class type at the point of deletion and the complete class has a
non-trivial destructor or a deallocation function, the behavior is undefined.
6 The delete-expression will invoke the destructor (if any) for the object or the elements of the array being
deleted. In the case of an array, the elements will be destroyed in order of decreasing address (that is, in
reverse order of the completion of their constructor; see 12.6.2).
7 The delete-expression will call a deallocation function (3.7.3.2).
8 [Note: An implementation provides default definitions of the
global deallocation functions
operator delete() for non-arrays (18.4.1.1) and operator delete[]() for arrays (18.4.1.2).
A C + + program can provide alternative definitions of these functions (17.4.3.4), and/or class-specific versions
(12.5). ] When the keyword delete in a delete-expression is preceded by the unary :: operator, the
global deallocation function is used to deallocate the storage.
9 Access and ambiguity control are done for both the deallocation function and th destructor (12.4, 12.5).