C
Ralf4711 schrieb:
camper schrieb:
Zwar sicher nicht Ursache des geschilderten Problems aber der Zuweisungsoperator von Matrix ist fehlerhaft (was nicht weiter auffällt, da er nicht benutzt wird).
Ansonsten könnte einiges zu diesem Code gesagt werden; bevor ich aber einen Roman schreibe, frage ich erst mal nach, ob eine Diskussion erwünscht ist.
was meinst du mit zuweisungsoperator von matrix?
die methodendeklarationen waren so durch die aufgabe vorgegeben, also wir sollten nur die rümpfe implementieren.
An der Deklaration ist nichts auszusetzen.
Was passiert, wenn in main noch ein
Bt = B;
eingefügt wird?
Ralf4711 schrieb:
wenn ich ein neues projekt erstelle und alles in einer datei unterbringe, bekomme ich einen linkerfehler!?
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Matrix<double> const &)" (??6@YAAAV?basic_ostream@DU?basic\_ostream@DU?basic_ostream@DU?char_traits@D@std@@@std@@AAV01@ABV?$Matrix@N@@@Z) referenced in function _main ConsoleApplication2 c:\Users\r. peglow\documents\visual studio 2015\Projects\ConsoleApplication2\ConsoleApplication2\Source.obj 1
Der Fehler dürfte auch für den *-Operator auftreten (ebenso + wenn er verwendet würde).
Der Grund hierfür liegt darin, dass die friend-Deklarationen in der Definition des Klassentemplates nicht zu den späteren Definitionen passen.
Ich beschränke mich mal auf den *-Operator, für die anderen gilt es analog:
template <typename T> class Matrix
{
...
friend Matrix<T> operator*(const Matrix<T> &ma, const Matrix<T> &mb);
};
template <typename T> Matrix<T> operator*(const Matrix<T> &ma, const Matrix<T> &mb)
{
...
Die friend-Deklaration in der Definition von Matrix deklariert gewöhnliche Funktionen als friend. Die spätere Definition definiert ein Funktionstemplate.
Die Tatsache, dass sie gleichen Funktionssignaturen haben, führt nicht dazu dass
Matrix<int> operator*(const Matrix<int>&, const Matrix<int>&)
und
Matrix<int> operator*<int>(const Matrix<int>&, const Matrix<int>&)
die gleichen Funktionen wären.
Was passiert also wenn der Compiler den Ausdruck ABt sieht? Er findet zwei Funktionen, die passen könnten, die gewöhnliche Funktion
Matrix<double> operator(const Matrix<double>&, const Matrix<double>&)
und das Template
Matrix<T> operator*(const Matrix<T> &ma, const Matrix<T> &mb)
mit der Spezialisierung T=double. Beide passen gleich gut und die Überladungsregeln besagen, dass wenn zwei Kandidaten gleich gut sind, und einer eine gewöhnliche Funktion, der andere eine Templatespezialisierung ist, die gewöhnliche Funktion ausgewählt wird. Dummerweise existiert für diese gewöhnliche Funktion keine Definition und das bringt den Linker in Schwierigkeiten...
Versuchen wir, die Definition zu korrigieren, dass sieht zur friend-Deklaration passt, wird es sofort schwierig.
Natürlich könnte man eine Definition für T=double geben
Matrix<double> operator*(const Matrix<double> &ma, const Matrix<double> &mb)
{
...
}
und dann noch für int
Matrix<int> operator*(const Matrix<int> &ma, const Matrix<int> &mb)
usw. aber das ist offensichtlich keine allgemeine Lösung, die für jedes sinnvolle Argument T passt. Tatsächlich gibt es keine Möglichkeit, die in der friend-Deklaration deklarierten Funktion für alle T ausserhalb der Matrix-Definition zu definieren.
Sollen die friends also unverändert erhalten bleiben, kann die Definition nur inline innerhalb der Matrix-Definition erfolgen:
template <typename T> class Matrix
{
...
friend Matrix<T> operator*(const Matrix<T> &ma, const Matrix<T> &mb)
{
...
}
};
Alternativ können wir beim Funktionstemplate verbleiben und die friend-Deklaration anpassen:
template <typename T> class Matrix
{
...
// macht das Funktionstemplate zum friend, alle Spezialisierungen des friend-Templates werden zu
// friends jeder Matrix-Spezialisierung (also mehr friend als nötig, dafür geringerer Schreibaufwand)
template <typename U> friend Matrix<U> operator*(const Matrix<U> &ma, const Matrix<U> &mb);
};
oder
template <typename T> class Matrix;
template <typename T> friend Matrix<T> operator*(const Matrix<T> &ma, const Matrix<T> &mb);
template <typename T> class Matrix
{
...
friend Matrix<T> operator*<T>(const Matrix<T> &ma, const Matrix<T> &mb);
};