Zaprzyjaźnienie przeciążonych op. << i >> z szab

0

Witam wszystkich serdecznie.
Nie wiem czy temat ma poprawne nazewnictwo, z tego względu, że te pojęcia są dla mnie nadal nowością ;) Myślę, że wklejenie części kodu rozwieje wszelkie wątpliwości. Próbowałem wykonać taką karkołomną konstrukcję, jak w temacie i MS Visual Studio niestety nie chce jej przełknąć.

klasa: (Pominąłem, z mojego punktu widzenia, nieistotną dla problemu część kodu)

template <class T>
class macierz
{
	friend ostream & ostream::operator<< (ostream & strumien, macierz<T> & M);
	friend istream & istream::operator>> (istream & strumien, macierz<T> & M);

	T **t;
	int w,k;

	public:
		macierz(int w, int k);
		macierz(macierz &w);
		macierz();
		~macierz();
		macierz(const int ** tablica, int wiersze, int kolumny);
		macierz<T> & set(int x, int y, T var);
		T get(int x, int y);
		macierz<T> & wyswietl() const;
		macierz operator + (macierz &right);
		macierz operator - (const macierz &right);
		macierz & operator = (const macierz &kopiowana);
		T & operator() (int x, int y);
		int getxsize() const;
		int getysize() const;
};

i same operatory

template <class T>
ostream & operator << (ostream & strumien, macierz<T> & M)
{
	for (int i=0; i<M.getysize(); i++)
	{
		for (int j=0; j<M.getxsize(); j++)
		{
			strumien << M.get(i,j) << "\t";
		}
		strumien << endl;
	}
	return strumien;
}

template <class T>
istream & operator >> (istream & strumien, macierz<T> & M)
{
	T temp;
	for (int i=0; i<M.getysize(); i++)
	{
		for (int j=0; j<M.getxsize(); j++)
		{
			strumien >> temp;
			M.set(i,j,temp);
		}
	}
	return strumien;
}

Jak można się domyślić, metody getysize i getxsize zwracają odpowiednio ilość wierszy i ilość kolumn macierzy (czyli to, do czego chce mieć dostęp poprzez zaprzyjaźnienie operatorów). Metody te zostały stworzone jako rozwiązanie tymczasowe, aby sprawdzić czy przeciążone operatory w ogóle działają. Docelowo metod tych nie ma być. Program kompiluje się pięknie, kiedy nie próbuję zaprzyjaźnić przeciążonych operatorów z klasą, a właściwie jej szablonem.

Visual wypluwa błędy:

Error 1 error C2245: non-existent member function 'std::basic_ostream<_Elem,_Traits>::operator <<' specified as friend (member function signature does not match any overload) d:\studia\po\macierz\macierz\macierz.cpp 9 macierz
Error 2 error C2245: non-existent member function 'std::basic_istream<_Elem,_Traits>::operator >>' specified as friend (member function signature does not match any overload) d:\studia\po\macierz\macierz\macierz.cpp 10 macierz
Error 3 error C2245: non-existent member function 'std::basic_ostream<_Elem,_Traits>::operator <<' specified as friend (member function signature does not match any overload) d:\studia\po\macierz\macierz\macierz.cpp 9 macierz
Error 4 error C2245: non-existent member function 'std::basic_istream<_Elem,_Traits>::operator >>' specified as friend (member function signature does not match any overload) d:\studia\po\macierz\macierz\macierz.cpp 10 macierz
Error 5 error C2245: non-existent member function 'std::basic_ostream<_Elem,_Traits>::operator <<' specified as friend (member function signature does not match any overload) d:\studia\po\macierz\macierz\macierz.cpp 9 macierz
Error 6 error C2245: non-existent member function 'std::basic_istream<_Elem,_Traits>::operator >>' specified as friend (member function signature does not match any overload) d:\studia\po\macierz\macierz\macierz.cpp 10 macierz

Linia 9 i 10 to deklaracje przyjaźni (tutaj też nie wiem czy to dobre określenie) operatorów w klasie macierz.

Da się w ogóle zaprzyjaźnić tak przeciążone operatory z szablonem klasy?

0
template <typename T>
class macierz;

template <typename T>
ostream& operator<<(ostream&, const macierz<T>&);

template <typename T>
class macierz
{
  friend ostream& operator<< <>(ostream&, const macierz<T>&);
  //...
};

template <typename T>
ostream& operator<<(ostream& ostr, const macierz<T>& m)
{
  //...
}

Analogicznie dla operatora >>. Coś się może nie zgadzać, pisałem z pamięci.

0

a prawda jest taka, że dobrze napiłeś klasę i operatory, w efekcie ta przyjaźń jest zupełnie zbędna (operatory nie używają chronionych lub prywatnych symboli klasy)!
Jedynie czego w kodzie brakuje to const tu i ówdzie.

0

Fanael: Nie rozumiem trochę na czym ta sztuczka miała polegać. Chodzi o deklarację klasy i przeciążonych operatorów przed definicjami? W każdym razie, takie rozwiązanie także wywala błędy:

Error 5 error LNK2019: unresolved external symbol "class std::basic_istream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_istream<char,struct std::char_traits<char> > &,class macierz<struct point="point"> &)" (??5@YAAAV?$basic_istream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$macierz@Upoint@@@@@Z) referenced in function _main macierz.obj macierz
Error 6 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 macierz<struct point="point"> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$macierz@Upoint@@@@@Z) referenced in function _main macierz.obj macierz
Error 7 error LNK2019: unresolved external symbol "class std::basic_istream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_istream<char,struct std::char_traits<char> > &,class macierz<float> &)" (??5@YAAAV?$basic_istream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$macierz@M@@@Z) referenced in function "void __cdecl main1(void)" (?main1@@YAXXZ) macierz.obj macierz
Error 8 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 macierz<float> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$macierz@M@@@Z) referenced in function "void __cdecl main1(void)" (?main1@@YAXXZ) macierz.obj macierz
Error 9 fatal error LNK1120: 4 unresolved externals D:\studia\PO\macierz\Debug\macierz.exe macierz

MarekR22: consty rzeczywiście powinny być, zapomniałem o nich ;)
Zamysł był taki, żeby nie tworzyć metod getxsize i getysize, ale w przeciążonych operatorach odwoływać się bezpośrednio do pól w i k klasy.

Szczerze mówiąc, nie muszę tego napisać w ten sposób, ale wpadłem na pomysł zaprzyjaźnienia tych operatorów, nie udało mi się i chce to zrobić, dla własnej satysfakcji ;)

Będę wdzięczny za wszystkie rady ;)

0
friend ostream & ostream::operator<< (ostream & strumien, macierz<T> & M);
friend istream & istream::operator>> (istream & strumien, macierz<T> & M);

A co te istream:: i ostream:: tam robi?

Spróbuj tak:

template <class T> class macierz
{
	(...)

	template<class T2> friend ostream& operator<< (ostream&, macierz<T2>&);
	template<class T2> friend istream& operator>> (istream&, macierz<T2>&);
};
0

raczej powinno być tak jak napisał na samym początku (ale jak już pisałem wyżej te przyjaźnie są zbędne).
Zresztą przeczytajcie łaskawie ten błąd kompilatora:

kompilator napisał(a)

Error 1 error C2245: non-existent member function 'std::basic_ostream<_Elem,_Traits>::operator <<' specified as friend (member function signature does not match any overload) d:\studia\po\macierz\macierz\macierz.cpp 9 macierz

Czyli deklaracja jest poprawna, ale skopane są relacje pomiędzy deklaracjami!
Przed klasą trzeb wstawić definicję szablonów tych operatorów lub wstawić ich deklarację.

0
MarekR22 napisał(a)

raczej powinno być tak jak napisał na samym początku

No raczej nie. Sam wskazałeś treść błędu, który jasno mówi, że nastąpiła próba zaprzyjaźnienia operatorów/metod, których obie klasy po prostu nie mają (zwróć uwagę na xstream::operator). I mieć nie mogą, bo operatory w tej formie są funkcjami, operatorami globalnymi ;) To pierwsza sprawa. Druga to to, że o ile VC łyknie formę

template<class T> friend ostream & operator<< (ostream &strumien, macierz<T>&);

to GCC już nie. Dlatego podałem wersję z parametrem T2.

0

nie masz racji bo, tą jego linkę należy uznać za przypadek użycia szablonu! Problem polega na tym, że w tym momencie kompilator nie jest świadomy o istnieniu tego szablonu dla tego operatora i dlatego narzeka. Czyli błąd siedzi w kodzie, którego nie podał (a raczej w złej kolejności kodu który podał).

ale zamiast się wykłócać poczekajmy na reakcję shaker. Moim zdaniem nie powinien kombinować i wywalić te przyjaźnie i wtedy problem nie istnieje, a nasza dyskusja jest jałowa.

0

Dziekuje wszystkim za odpowiedzi ;)

Dodanie template <class T> przed "zaprzyjaźnianiem" operatorów w klasie pomogło. Deklaracja klasy i operatorów przed definicjami nie jest konieczna. Z class T2 pokombinuję, jak znajdę chwilę czasu ;)

obecnie klasa wygląda tak:

template <class T>
class macierz
{
	template <class T> friend ostream & operator<< (ostream & strumien, macierz<T> & M);
	template <class T> friend istream & operator>> (istream & strumien, macierz<T> & M);

	T **t;
	int w,k;

	public:
		macierz(int w, int k);
		macierz(macierz &w);
		macierz();
		~macierz();
		macierz(const int ** tablica, int wiersze, int kolumny);
		macierz<T> & set(int x, int y, T var);
		T get(int x, int y);
		macierz<T> & wyswietl() const;
		macierz operator + (macierz &right);
		macierz operator - (const macierz &right);
		macierz & operator = (const macierz &kopiowana);
		T & operator() (int x, int y);
};

Namawialiście mnie na nie zaprzyjaźnianie operatorów z klasą. To kwestia tego, że problem istniał akurat w tym miejscu, czy jakichś dobrych praktyk programistycznych? ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1