<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Problem mit Klassentemplates]]></title><description><![CDATA[<p>hallo ich habe folgendes Programm:</p>
<pre><code>//main.cpp
#include &lt;iostream&gt;
#include &quot;Matrix.hpp&quot;

int main()
{
	Matrix &lt;double&gt;A(3, 4); //Neue 3*4-Matrix A erstellen

	//Matrix A mit den in der Aufgabe vorgegebenen Werten füllen
	for (int i = 0; i &lt; 3; i++)
	{
		for (int j = 0; j &lt; 4; j++)
		{
			A[i][j] = 13.5*i+j+1.4; 
		}

	}

	Matrix&lt;double&gt; B = A; //Matrix B als Kopie von Matrix A erstellen
	Matrix&lt;double&gt; Bt = B.Transpose(); //Matrix B transponieren
	Matrix&lt;double&gt; AB = A*Bt; //Matrix A mit transponierter Matrix B multiplizieren
	cout &lt;&lt; AB&lt;&lt;endl; //Ergebnis auf dem Bildschirm ausgeben

	system(&quot;cls&quot;);
	return 0;
}
</code></pre>
<pre><code>//matrix.hpp
#ifndef _MATRIX_H_
#define _MATRIX_H_

#include &lt;iostream&gt;
#include &lt;cassert&gt;
using namespace std;

template &lt;typename T&gt; class Zeile
{
	//Instanzvariablen
	T *z;
	int size;

public:
	//Konstruktor und Destruktor
	Zeile(int s);
	~Zeile();

	//Liefert eine Referenz auf das i-te Element der Zeile, fängt Bereichsüberschreitungen ab
	T&amp; operator[](int i)
	{
		assert(i &gt;= 0 &amp;&amp; i &lt; size);
		return *(z+i);
	}

	//Liefert eine konstante Referenz auf das i-te Element der Zeile, fängt Bereichsüberschreitungen
	const T&amp; operator[](int i) const
	{
		assert(i &gt;= 0 &amp;&amp; i &lt; size);
		return *(z+i);
	}
};

template &lt;typename T&gt; class Matrix
{
	//Instanzvariablen
	Zeile&lt;T&gt; **mat;
	int nrows, ncols;

public:
	//Konstruktoren und Destruktoren
	Matrix&lt;T&gt;(int _nrows, int _ncols);
	Matrix&lt;T&gt;(int z, int s, T wert);
	Matrix&lt;T&gt;(const Matrix&lt;T&gt;&amp;);
	~Matrix&lt;T&gt;();

	//Getter-Methoden
	int GetRows() const
	{
		return nrows;
	}

	int GetCols() const
	{
		return ncols;
	}

	//Methoden-Prototypen?
	Matrix&lt;T&gt; Transpose();
	inline Zeile&lt;T&gt;&amp; operator[](int i);
	inline const Zeile&lt;T&gt;&amp; operator[](int i) const;
	Matrix&lt;T&gt;&amp; operator=(const Matrix&lt;T&gt; &amp;ma);	
	friend ostream&amp; operator&lt;&lt;(ostream &amp;os, const Matrix&lt;T&gt; &amp;m);
	friend Matrix&lt;T&gt; operator+(const Matrix &amp;ma&lt;T&gt;, const Matrix&lt;T&gt; &amp;mb);
	friend Matrix&lt;T&gt; operator*(const Matrix &amp;ma&lt;T&gt;, const Matrix&lt;T&gt; &amp;mb);
};

#endif
</code></pre>
<pre><code>//matrix.cpp
#include &quot;Matrix.hpp&quot;
using namespace std;

template &lt;typename T&gt;Zeile&lt;T&gt;::Zeile(int s)
{
	z = new T[s];
	size = s;

	for (int i = 0; i &lt; s; i++)
	{
		z[i] = 0;
	}
}

template &lt;typename T&gt;Zeile::~Zeile()
{
	delete z;
	z = 0;
}

template &lt;typename T&gt; Matrix&lt;T&gt;::Matrix(int _nrows, int _ncols)
{

	mat = new Zeile&lt;T&gt;*[_nrows];

	for (int i = 0; i &lt; _nrows; i++)
	{
		*(mat+i) = new Zeile&lt;T&gt;(_ncols);
	}

	nrows = _nrows;
	ncols = _ncols;
}

template &lt;typename T&gt; Matrix&lt;T&gt;::Matrix(int _nrows, int _ncols, T wert)
{
	mat = new Zeile&lt;T&gt;*[_nrows];

	for (int i = 0; i &lt; _nrows; i++)
	{
		*(mat+i) = new Zeile&lt;T&gt;(_ncols);
	}

	for (int i = 0; i &lt; _nrows; i++)
	{
		for (int j = 0; j &lt; _ncols; j++)
		{
			(**(mat+i))[j] = wert;
		}
	}

	nrows = _nrows;
	ncols = _ncols;
}

template &lt;typename T&gt;Matrix&lt;T&gt;::Matrix(const Matrix &amp;m)
{
	nrows = m.GetRows();
	ncols = m.GetCols();

	mat = new Zeile&lt;T&gt;*[nrows];

	for (int i = 0; i &lt; nrows; i++)
	{
		*(mat + i) = new Zeile&lt;T&gt;(ncols);
	}

	for (int i = 0; i &lt; nrows; i++)
	{
		for (int j = 0; j &lt; ncols; j++)
		{
			(**(mat + i))[j] = m[i][j];
		}
	}
}

template &lt;typename T&gt; Matrix&lt;T&gt;::~Matrix()
{
	for (int i = 0; i &lt; nrows; i++)
	{
		delete *(mat + i);
		*(mat + i) = 0;
	}

	delete mat;
}

template &lt;typename T&gt; Matrix&lt;T&gt; Matrix&lt;T&gt;::Transpose()
{
	Matrix&lt;T&gt; tmp(ncols, nrows);

	for (int i = 0; i &lt; ncols; i++)
	{
		for (int j = 0; j &lt; nrows; j++)
		{
			tmp[i][j] = (**(mat + j))[i];
		}
	}

	return tmp;
}

template &lt;typename T&gt; Zeile&lt;T&gt;&amp; Matrix&lt;T&gt;::operator[](int i)
{
	return *(*(mat+i));
}

template &lt;typename T&gt; const Zeile&lt;T&gt;&amp; Matrix&lt;T&gt;::operator[](int i) const
{
	return *(*(mat+i));
}

template &lt;typename T&gt; Matrix&lt;T&gt;&amp; Matrix&lt;T&gt;::operator=(const Matrix&lt;T&gt; &amp;ma)
{
	for (int i = 0; i &lt; nrows; i++)
	{
		for (int j = 0; j &lt; ncols; j++)
		{
			(**(mat + i))[j] = ma[i][j];
		}
	}

	return *this;
}

template &lt;typename T&gt;Matrix&lt;T&gt; operator+(const Matrix&lt;T&gt; &amp;ma, const Matrix&lt;T&gt; &amp;mb)
{
	Matrix&lt;T&gt; tmp(ma);

	for (int i = 0; i &lt; ma.nrows; i++)
	{
		for (int j = 0; j &lt; ma.ncols; j++)
		{
			tmp[i][j] = tmp[i][j] + mb[i][j];
		}
	}

	return tmp;
}

template &lt;typename T&gt; Matrix&lt;T&gt; operator*(const Matrix&lt;T&gt; &amp;ma, const Matrix&lt;T&gt; &amp;mb)
{
	Matrix&lt;T&gt; mul(ma.nrows, mb.ncols);

	for (int i = 0; i &lt; mul.nrows; i++)
	{
		for (int j = 0; j &lt; mul.ncols; j++)
		{
			for (int k = 0; k &lt;ma.ncols ; k++)
			{
				mul[i][j] = mul[i][j] + ma[i][k] * mb[k][j];
			}
		}
	}
	return mul;
}

template &lt;typename T&gt; ostream&amp; operator&lt;&lt;(ostream &amp;os, const Matrix&lt;T&gt; &amp;m)
{
	for (int i = 0; i &lt; m.nrows; i++)
	{
		for (int j = 0; j &lt; m.ncols; j++)
		{
			os &lt;&lt; m[i][j]&lt;&lt;&quot; &quot;;
		}
		os &lt;&lt; endl;
	}

	return os;
}
</code></pre>
<p>die aufgabe lautete, dieses programm zuerst für integer-variablen zu erstellen (funktionierte) und dann um klassentemplates zu erweitern. visual studio tut zumindest so, als würde es kompilieren, gibt dann aber nur die zahlen des ursprünglichen programms aus.</p>
<p>habe ich da irgendetwas übersehen? was könnte da falsch sein?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/338414/problem-mit-klassentemplates</link><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 15:06:36 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/338414.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 14 Jun 2016 11:50:00 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Problem mit Klassentemplates on Tue, 14 Jun 2016 11:50:00 GMT]]></title><description><![CDATA[<p>hallo ich habe folgendes Programm:</p>
<pre><code>//main.cpp
#include &lt;iostream&gt;
#include &quot;Matrix.hpp&quot;

int main()
{
	Matrix &lt;double&gt;A(3, 4); //Neue 3*4-Matrix A erstellen

	//Matrix A mit den in der Aufgabe vorgegebenen Werten füllen
	for (int i = 0; i &lt; 3; i++)
	{
		for (int j = 0; j &lt; 4; j++)
		{
			A[i][j] = 13.5*i+j+1.4; 
		}

	}

	Matrix&lt;double&gt; B = A; //Matrix B als Kopie von Matrix A erstellen
	Matrix&lt;double&gt; Bt = B.Transpose(); //Matrix B transponieren
	Matrix&lt;double&gt; AB = A*Bt; //Matrix A mit transponierter Matrix B multiplizieren
	cout &lt;&lt; AB&lt;&lt;endl; //Ergebnis auf dem Bildschirm ausgeben

	system(&quot;cls&quot;);
	return 0;
}
</code></pre>
<pre><code>//matrix.hpp
#ifndef _MATRIX_H_
#define _MATRIX_H_

#include &lt;iostream&gt;
#include &lt;cassert&gt;
using namespace std;

template &lt;typename T&gt; class Zeile
{
	//Instanzvariablen
	T *z;
	int size;

public:
	//Konstruktor und Destruktor
	Zeile(int s);
	~Zeile();

	//Liefert eine Referenz auf das i-te Element der Zeile, fängt Bereichsüberschreitungen ab
	T&amp; operator[](int i)
	{
		assert(i &gt;= 0 &amp;&amp; i &lt; size);
		return *(z+i);
	}

	//Liefert eine konstante Referenz auf das i-te Element der Zeile, fängt Bereichsüberschreitungen
	const T&amp; operator[](int i) const
	{
		assert(i &gt;= 0 &amp;&amp; i &lt; size);
		return *(z+i);
	}
};

template &lt;typename T&gt; class Matrix
{
	//Instanzvariablen
	Zeile&lt;T&gt; **mat;
	int nrows, ncols;

public:
	//Konstruktoren und Destruktoren
	Matrix&lt;T&gt;(int _nrows, int _ncols);
	Matrix&lt;T&gt;(int z, int s, T wert);
	Matrix&lt;T&gt;(const Matrix&lt;T&gt;&amp;);
	~Matrix&lt;T&gt;();

	//Getter-Methoden
	int GetRows() const
	{
		return nrows;
	}

	int GetCols() const
	{
		return ncols;
	}

	//Methoden-Prototypen?
	Matrix&lt;T&gt; Transpose();
	inline Zeile&lt;T&gt;&amp; operator[](int i);
	inline const Zeile&lt;T&gt;&amp; operator[](int i) const;
	Matrix&lt;T&gt;&amp; operator=(const Matrix&lt;T&gt; &amp;ma);	
	friend ostream&amp; operator&lt;&lt;(ostream &amp;os, const Matrix&lt;T&gt; &amp;m);
	friend Matrix&lt;T&gt; operator+(const Matrix &amp;ma&lt;T&gt;, const Matrix&lt;T&gt; &amp;mb);
	friend Matrix&lt;T&gt; operator*(const Matrix &amp;ma&lt;T&gt;, const Matrix&lt;T&gt; &amp;mb);
};

#endif
</code></pre>
<pre><code>//matrix.cpp
#include &quot;Matrix.hpp&quot;
using namespace std;

template &lt;typename T&gt;Zeile&lt;T&gt;::Zeile(int s)
{
	z = new T[s];
	size = s;

	for (int i = 0; i &lt; s; i++)
	{
		z[i] = 0;
	}
}

template &lt;typename T&gt;Zeile::~Zeile()
{
	delete z;
	z = 0;
}

template &lt;typename T&gt; Matrix&lt;T&gt;::Matrix(int _nrows, int _ncols)
{

	mat = new Zeile&lt;T&gt;*[_nrows];

	for (int i = 0; i &lt; _nrows; i++)
	{
		*(mat+i) = new Zeile&lt;T&gt;(_ncols);
	}

	nrows = _nrows;
	ncols = _ncols;
}

template &lt;typename T&gt; Matrix&lt;T&gt;::Matrix(int _nrows, int _ncols, T wert)
{
	mat = new Zeile&lt;T&gt;*[_nrows];

	for (int i = 0; i &lt; _nrows; i++)
	{
		*(mat+i) = new Zeile&lt;T&gt;(_ncols);
	}

	for (int i = 0; i &lt; _nrows; i++)
	{
		for (int j = 0; j &lt; _ncols; j++)
		{
			(**(mat+i))[j] = wert;
		}
	}

	nrows = _nrows;
	ncols = _ncols;
}

template &lt;typename T&gt;Matrix&lt;T&gt;::Matrix(const Matrix &amp;m)
{
	nrows = m.GetRows();
	ncols = m.GetCols();

	mat = new Zeile&lt;T&gt;*[nrows];

	for (int i = 0; i &lt; nrows; i++)
	{
		*(mat + i) = new Zeile&lt;T&gt;(ncols);
	}

	for (int i = 0; i &lt; nrows; i++)
	{
		for (int j = 0; j &lt; ncols; j++)
		{
			(**(mat + i))[j] = m[i][j];
		}
	}
}

template &lt;typename T&gt; Matrix&lt;T&gt;::~Matrix()
{
	for (int i = 0; i &lt; nrows; i++)
	{
		delete *(mat + i);
		*(mat + i) = 0;
	}

	delete mat;
}

template &lt;typename T&gt; Matrix&lt;T&gt; Matrix&lt;T&gt;::Transpose()
{
	Matrix&lt;T&gt; tmp(ncols, nrows);

	for (int i = 0; i &lt; ncols; i++)
	{
		for (int j = 0; j &lt; nrows; j++)
		{
			tmp[i][j] = (**(mat + j))[i];
		}
	}

	return tmp;
}

template &lt;typename T&gt; Zeile&lt;T&gt;&amp; Matrix&lt;T&gt;::operator[](int i)
{
	return *(*(mat+i));
}

template &lt;typename T&gt; const Zeile&lt;T&gt;&amp; Matrix&lt;T&gt;::operator[](int i) const
{
	return *(*(mat+i));
}

template &lt;typename T&gt; Matrix&lt;T&gt;&amp; Matrix&lt;T&gt;::operator=(const Matrix&lt;T&gt; &amp;ma)
{
	for (int i = 0; i &lt; nrows; i++)
	{
		for (int j = 0; j &lt; ncols; j++)
		{
			(**(mat + i))[j] = ma[i][j];
		}
	}

	return *this;
}

template &lt;typename T&gt;Matrix&lt;T&gt; operator+(const Matrix&lt;T&gt; &amp;ma, const Matrix&lt;T&gt; &amp;mb)
{
	Matrix&lt;T&gt; tmp(ma);

	for (int i = 0; i &lt; ma.nrows; i++)
	{
		for (int j = 0; j &lt; ma.ncols; j++)
		{
			tmp[i][j] = tmp[i][j] + mb[i][j];
		}
	}

	return tmp;
}

template &lt;typename T&gt; Matrix&lt;T&gt; operator*(const Matrix&lt;T&gt; &amp;ma, const Matrix&lt;T&gt; &amp;mb)
{
	Matrix&lt;T&gt; mul(ma.nrows, mb.ncols);

	for (int i = 0; i &lt; mul.nrows; i++)
	{
		for (int j = 0; j &lt; mul.ncols; j++)
		{
			for (int k = 0; k &lt;ma.ncols ; k++)
			{
				mul[i][j] = mul[i][j] + ma[i][k] * mb[k][j];
			}
		}
	}
	return mul;
}

template &lt;typename T&gt; ostream&amp; operator&lt;&lt;(ostream &amp;os, const Matrix&lt;T&gt; &amp;m)
{
	for (int i = 0; i &lt; m.nrows; i++)
	{
		for (int j = 0; j &lt; m.ncols; j++)
		{
			os &lt;&lt; m[i][j]&lt;&lt;&quot; &quot;;
		}
		os &lt;&lt; endl;
	}

	return os;
}
</code></pre>
<p>die aufgabe lautete, dieses programm zuerst für integer-variablen zu erstellen (funktionierte) und dann um klassentemplates zu erweitern. visual studio tut zumindest so, als würde es kompilieren, gibt dann aber nur die zahlen des ursprünglichen programms aus.</p>
<p>habe ich da irgendetwas übersehen? was könnte da falsch sein?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2498789</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2498789</guid><dc:creator><![CDATA[Ralf4711]]></dc:creator><pubDate>Tue, 14 Jun 2016 11:50:00 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit Klassentemplates on Tue, 14 Jun 2016 12:07:56 GMT]]></title><description><![CDATA[<blockquote>
<p>visual studio tut zumindest so, als würde es kompilieren, gibt dann aber nur die zahlen des ursprünglichen programms aus.</p>
</blockquote>
<p>Mal mal nen Rebuild All.</p>
<p>Desweiteren kannst du die Memberdefinitionen eines Klassentemplates nicht separat in eine Datei schreiben, es sei denn, du inkludierst die .cpp-Datei im Header direkt unter der Klassendefinition.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2498791</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2498791</guid><dc:creator><![CDATA[walnuss]]></dc:creator><pubDate>Tue, 14 Jun 2016 12:07:56 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit Klassentemplates on Tue, 14 Jun 2016 12:15:13 GMT]]></title><description><![CDATA[<p>Wenn &quot;Rebuild all&quot; nichts ändert, hast du wohl das Projekt kaputtkonfiguriert. Das wird sich per Ferndiagnose wohl schlecht lösen lasse =&gt; neues Projekt mit den alten Dateien bauen.</p>
<p>Grundsätzlich müssen Templates aber ausschließlich im Header implementiert werden. Deine Aufteilung in .h und .cpp wird damit also nicht (portabel <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title="*)"
      alt="😉"
    /> funktionieren.</p>
<p>[*] möglicherweise gibt es da in VS einer Microsoft Erweiterung, mit der es dann doch übersetzt.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2498794</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2498794</guid><dc:creator><![CDATA[manni66]]></dc:creator><pubDate>Tue, 14 Jun 2016 12:15:13 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit Klassentemplates on Tue, 14 Jun 2016 15:43:02 GMT]]></title><description><![CDATA[<p>Zwar sicher nicht Ursache des geschilderten Problems aber der Zuweisungsoperator von Matrix ist fehlerhaft (was nicht weiter auffällt, da er nicht benutzt wird).<br />
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.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2498840</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2498840</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 14 Jun 2016 15:43:02 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit Klassentemplates on Tue, 14 Jun 2016 17:01:14 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<p>Zwar sicher nicht Ursache des geschilderten Problems aber der Zuweisungsoperator von Matrix ist fehlerhaft (was nicht weiter auffällt, da er nicht benutzt wird).<br />
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.</p>
</blockquote>
<p>was meinst du mit zuweisungsoperator von matrix?<br />
die methodendeklarationen waren so durch die aufgabe vorgegeben, also wir sollten nur die rümpfe implementieren.</p>
<p>wenn ich ein neues projekt erstelle und alles in einer datei unterbringe, bekomme ich einen linkerfehler!?</p>
<p>Severity Code Description Project File Line Suppression State<br />
Error LNK2019 unresolved external symbol &quot;class std::basic_ostream&lt;char,struct std::char_traits&lt;char&gt; &gt; &amp; __cdecl operator&lt;&lt;(class std::basic_ostream&lt;char,struct std::char_traits&lt;char&gt; &gt; &amp;,class Matrix&lt;double&gt; const &amp;)&quot; (??6@YAAAV?<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>b</mi><mi>a</mi><mi>s</mi><mi>i</mi><mi>c</mi><mi mathvariant="normal">_</mi><mi>o</mi><mi>s</mi><mi>t</mi><mi>r</mi><mi>e</mi><mi>a</mi><mi>m</mi><mi mathvariant="normal">@</mi><mi>D</mi><mi>U</mi><mo>?</mo></mrow><annotation encoding="application/x-tex">basic\_ostream@DU?</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.69444em;"></span><span class="strut bottom" style="height:1.00444em;vertical-align:-0.31em;"></span><span class="base textstyle uncramped"><span class="mord mathit">b</span><span class="mord mathit">a</span><span class="mord mathit">s</span><span class="mord mathit">i</span><span class="mord mathit">c</span><span class="mord mathrm" style="margin-right:0.02778em;">_</span><span class="mord mathit">o</span><span class="mord mathit">s</span><span class="mord mathit">t</span><span class="mord mathit" style="margin-right:0.02778em;">r</span><span class="mord mathit">e</span><span class="mord mathit">a</span><span class="mord mathit">m</span><span class="mord mathrm">@</span><span class="mord mathit" style="margin-right:0.02778em;">D</span><span class="mord mathit" style="margin-right:0.10903em;">U</span><span class="mclose">?</span></span></span></span>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</p>
<p>also um mal eine direkte frage zu stellen: habe ich das prinzip der anwendung von klassentemplates verstanden, oder ist das alles komplett falsch?</p>
<p>und natürlich ist eine diskussion erwünscht, außer sie steht im widerspruch zu obiger aussage, dass gewisse teile durch die aufgabe vorgegeben waren. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2498851</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2498851</guid><dc:creator><![CDATA[Ralf4711]]></dc:creator><pubDate>Tue, 14 Jun 2016 17:01:14 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit Klassentemplates on Tue, 14 Jun 2016 18:16:34 GMT]]></title><description><![CDATA[<p>Ralf4711 schrieb:</p>
<blockquote>
<p>camper schrieb:</p>
<blockquote>
<p>Zwar sicher nicht Ursache des geschilderten Problems aber der Zuweisungsoperator von Matrix ist fehlerhaft (was nicht weiter auffällt, da er nicht benutzt wird).<br />
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.</p>
</blockquote>
<p>was meinst du mit zuweisungsoperator von matrix?<br />
die methodendeklarationen waren so durch die aufgabe vorgegeben, also wir sollten nur die rümpfe implementieren.</p>
</blockquote>
<p>An der Deklaration ist nichts auszusetzen.<br />
Was passiert, wenn in main noch ein</p>
<pre><code class="language-cpp">Bt = B;
</code></pre>
<p>eingefügt wird?</p>
<p>Ralf4711 schrieb:</p>
<blockquote>
<p>wenn ich ein neues projekt erstelle und alles in einer datei unterbringe, bekomme ich einen linkerfehler!?</p>
<p>Severity Code Description Project File Line Suppression State<br />
Error LNK2019 unresolved external symbol &quot;class std::basic_ostream&lt;char,struct std::char_traits&lt;char&gt; &gt; &amp; __cdecl operator&lt;&lt;(class std::basic_ostream&lt;char,struct std::char_traits&lt;char&gt; &gt; &amp;,class Matrix&lt;double&gt; const &amp;)&quot; (??6@YAAAV?<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>b</mi><mi>a</mi><mi>s</mi><mi>i</mi><mi>c</mi><mi mathvariant="normal">_</mi><mi>o</mi><mi>s</mi><mi>t</mi><mi>r</mi><mi>e</mi><mi>a</mi><mi>m</mi><mi mathvariant="normal">@</mi><mi>D</mi><mi>U</mi><mo>?</mo></mrow><annotation encoding="application/x-tex">basic\_ostream@DU?</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.69444em;"></span><span class="strut bottom" style="height:1.00444em;vertical-align:-0.31em;"></span><span class="base textstyle uncramped"><span class="mord mathit">b</span><span class="mord mathit">a</span><span class="mord mathit">s</span><span class="mord mathit">i</span><span class="mord mathit">c</span><span class="mord mathrm" style="margin-right:0.02778em;">_</span><span class="mord mathit">o</span><span class="mord mathit">s</span><span class="mord mathit">t</span><span class="mord mathit" style="margin-right:0.02778em;">r</span><span class="mord mathit">e</span><span class="mord mathit">a</span><span class="mord mathit">m</span><span class="mord mathrm">@</span><span class="mord mathit" style="margin-right:0.02778em;">D</span><span class="mord mathit" style="margin-right:0.10903em;">U</span><span class="mclose">?</span></span></span></span>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</p>
</blockquote>
<p>Der Fehler dürfte auch für den *-Operator auftreten (ebenso + wenn er verwendet würde).<br />
Der Grund hierfür liegt darin, dass die friend-Deklarationen in der Definition des Klassentemplates nicht zu den späteren Definitionen passen.<br />
Ich beschränke mich mal auf den *-Operator, für die anderen gilt es analog:</p>
<pre><code class="language-cpp">template &lt;typename T&gt; class Matrix
{
...
    friend Matrix&lt;T&gt; operator*(const Matrix&lt;T&gt; &amp;ma, const Matrix&lt;T&gt; &amp;mb);
};

template &lt;typename T&gt; Matrix&lt;T&gt; operator*(const Matrix&lt;T&gt; &amp;ma, const Matrix&lt;T&gt; &amp;mb)
{
...
</code></pre>
<p>Die friend-Deklaration in der Definition von Matrix deklariert <em>gewöhnliche</em> Funktionen als friend. Die spätere Definition definiert ein Funktionstemplate.<br />
Die Tatsache, dass sie gleichen Funktionssignaturen haben, führt nicht dazu dass</p>
<pre><code class="language-cpp">Matrix&lt;int&gt; operator*(const Matrix&lt;int&gt;&amp;, const Matrix&lt;int&gt;&amp;)
</code></pre>
<p>und</p>
<pre><code class="language-cpp">Matrix&lt;int&gt; operator*&lt;int&gt;(const Matrix&lt;int&gt;&amp;, const Matrix&lt;int&gt;&amp;)
</code></pre>
<p>die gleichen Funktionen wären.<br />
Was passiert also wenn der Compiler den Ausdruck A<em>Bt sieht? Er findet zwei Funktionen, die passen könnten, die gewöhnliche Funktion<br />
Matrix&lt;double&gt; operator</em>(const Matrix&lt;double&gt;&amp;, const Matrix&lt;double&gt;&amp;)<br />
und das Template<br />
Matrix&lt;T&gt; operator*(const Matrix&lt;T&gt; &amp;ma, const Matrix&lt;T&gt; &amp;mb)<br />
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...</p>
<p>Versuchen wir, die Definition zu korrigieren, dass sieht zur friend-Deklaration passt, wird es sofort schwierig.<br />
Natürlich könnte man eine Definition für T=double geben</p>
<pre><code class="language-cpp">Matrix&lt;double&gt; operator*(const Matrix&lt;double&gt; &amp;ma, const Matrix&lt;double&gt; &amp;mb)
{
...
}
</code></pre>
<p>und dann noch für int</p>
<pre><code class="language-cpp">Matrix&lt;int&gt; operator*(const Matrix&lt;int&gt; &amp;ma, const Matrix&lt;int&gt; &amp;mb)
</code></pre>
<p>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.<br />
Sollen die friends also unverändert erhalten bleiben, kann die Definition nur inline innerhalb der Matrix-Definition erfolgen:</p>
<pre><code class="language-cpp">template &lt;typename T&gt; class Matrix
{
...
    friend Matrix&lt;T&gt; operator*(const Matrix&lt;T&gt; &amp;ma, const Matrix&lt;T&gt; &amp;mb)
    {
    ...
    }
};
</code></pre>
<p>Alternativ können wir beim Funktionstemplate verbleiben und die friend-Deklaration anpassen:</p>
<pre><code class="language-cpp">template &lt;typename T&gt; 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 &lt;typename U&gt; friend Matrix&lt;U&gt; operator*(const Matrix&lt;U&gt; &amp;ma, const Matrix&lt;U&gt; &amp;mb);
};
</code></pre>
<p>oder</p>
<pre><code class="language-cpp">template &lt;typename T&gt; class Matrix;
template &lt;typename T&gt; friend Matrix&lt;T&gt; operator*(const Matrix&lt;T&gt; &amp;ma, const Matrix&lt;T&gt; &amp;mb);
template &lt;typename T&gt; class Matrix
{
...
    friend Matrix&lt;T&gt; operator*&lt;T&gt;(const Matrix&lt;T&gt; &amp;ma, const Matrix&lt;T&gt; &amp;mb);
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2498863</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2498863</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 14 Jun 2016 18:16:34 GMT</pubDate></item></channel></rss>