Szablony, przeciążanie operatorów, dynamiczna alokacja... problemy

0

Uczę się C++, wydawało mi się że dość dobrze rozumiem jak dotąd, ale chyba jednak nie...
Doszedłem do szablonów i tu natknąłem się na zadanie, którego nie potrafię rozwiązać sensownie, a właściwie to w ogóle.

Mamy klasę szablonową K, w niej liczbę całkowitą - rozmiar tablicy oraz samą tablicę (dynamiczną) o typie zdefiniowanym przez użytkownika. W klasie mam przeciążyć operator odejmowania i napisać metodę wypisującą zawartość tablicy. Dla sprawdzenia mam stworzyć 3 obiekty typu float b1,b2,b3 i zrobić b3=b1-b2, po czym wypisać b3. Przy czym przy odejmowaniu jeśli tablice są różnych rozmiarów to wynikowy obiekt ma mieć tablicę o rozmiarze tej mniejszej z wejściowych tablic. Czyli np. b1 ma 5 elementów tablicę, b2 ma 3 elementy i zrobimy b3=b1-b2 to b3 ma tablicę 3 elementową i w niej odjęte od siebie tylko te 3 wyrazy które można odjąć ( w tym przypadku 2 ostatnie wyrazy z b1 będą pominięte).

Mój kod jak dotąd wygląda tak:

 
#include <iostream>

using namespace std;


template<typename Typ>
class K
{
private:
	int n;    //wielkosc tablicy
	Typ *T;   //tablica
public:
	K()
	{
		//pusty konstruktor
	}
	
	K(int roz);  //konstruktor
	~K();        //destruktor

	//operator odejmowania, z tym jest problem :/
	K operator- (K<Typ> obj)
	{
		int mniejszy;
		if(n < obj.n)
		{
			mniejszy=n;
		}
		else                    //szukam ktora z wejsciowych tablic jest mniejsza
		{
			mniejszy=obj.n;
		}

		for(int i=0;i<mniejszy;i++)
		{
			T[i]-=obj.T[i]; //odejmuje
		}
		return *this;     //zwracam
	}

	void wynik();    //metoda wyswietlajaca obiekt
};

template<typename Typ>
K<Typ>::K(int roz)
{
	n=roz;
	T=new Typ[n];
	for(int i=0;i<n;i++)
	{
		cout<<"Podaj "<<i+1<<" wyraz: ";   //konstruktor, wczytujacy dane
		cin>>T[i];
	}
}

template<typename Typ>
K<Typ>::~K()
{
	delete [] T;   //destruktor zwalnia pamiec
}


template<typename Typ>
void K<Typ>::wynik()
{
	for(int i=0;i<n;i++)
	{
		cout<<i+1<<" wyraz: "<<T[i]<<endl;      //metoda wypisujaca
	}
}

int main()
{
	K<float> b1(5), b2(3); //tworze obiekty
	K<float> b3;
	b3=b1-b2;  //odejmowanie
	b3.wynik();  //wypisanie
	system("PAUSE");
	return 0;
}

Tak, wiem że do obiektu b3 chcę wpisać dane jak nie mam na nie zaalokowanej pamięci. Niezbyt wiem jak zorganizować te konstruktory żeby to wszystko miało sens.
Piszę pod VisualC++ 2005, ale wiem że g++ zachowuje się akurat w tym przypadku znacznie inaczej. Tzn. kod działa inaczej. Próbowałem już to robić na 10 sposobów i dalej nie doszedłem do właściwego. Próbowałem tworzyć w operatorze obiekt pomocniczy i go zwracać, ale też był problem z alokacją.
Jak ustawię pracę krokową i śledzę operator odejmujący, to wydaje mi się że tablice w pętli odejmującej mają inne wartości niż powinny.

Z góry dzięki za wszelką pomoc.

0

Kurcze zapomniałem dopisać, że próbowałem "sztywno" alokować b3 żeby się zgadzało. Tzn. tak:

 
...
int main()
{
K<float> b1(5), b2(3); //tworze obiekty
	K<float> b3(3);    //na sztywno ustawiam sobie tu 3, żeby mi się zgadzało i wypełniam sobie np. zerami
	b3=b1-b2;  //odejmowanie
	b3.wynik();  //wypisanie
	system("PAUSE");
	return 0;
}

Więc teraz zdaje się, że mam gdzie zapisać wynikowe dane, a jednak nie idzie...

0

operator odejmowania nie powinien "psuć" żadnego z operandów.

K operator-(const K<Typ> &obj)const
  {
    K<Typ> tmp(n<obj.n?n:obj.n);
    for(int i=0;i<tmp.n;++i) tmp.T[i]=T[i]-obj.T[i]; //odejmuje
    return tmp; //zwracam
  }
0

A mógłbyś coś więcej napisać? Jak przekażę przez referencję, to przekażę oryginał, tak? I w czym to pomoże? I co ten const na końcu sygnatury oznacza? :P

No i nic to nie zmieniło, przy tworzeniu obiektu wewnątrz operatora dostawałem taki sam błąd jak tu: Debug Assertion Fail ...

0

Chyba problem rozwiązałem choć nie całkiem:

#include <iostream>

using namespace std;


template<typename Typ>
class K
{
private:
	int n;    //wielkosc tablicy
	Typ *T;   //tablica
public:
	K()
	{
		T=new Typ;//bezargumentowy konstruktor, inicjalizuje wskaźnik
	}
	
	K(int roz);  //konstruktor
	~K();        //destruktor


	K &operator= (K<Typ> &ob) //operator przypisania
	{
		if(this!=&ob)
		{
			if(n!=ob.n)
			{
				delete [] T;
				n=ob.n;
				T=new Typ[ob.n];
			}
			for(int i=0;i<n;i++)
			{
				T[i]=ob.T[i];
			}
		}
		return *this;
	}

	//operator odejmowania
	K operator-(const K<Typ> &obj)const
  {
	  int mniejszy;
	  if(n < obj.n)
		{
			mniejszy=n;
			K<Typ> tmp=*this;
		    for(int i=0;i<mniejszy;++i) 
			{
				tmp.T[i]=T[i]-obj.T[i];
			}	 
		    return tmp; 
		}
	  else 
		{
			mniejszy=obj.n;
			K<Typ> tmp=obj;
			for(int i=0;i<mniejszy;++i) 
			{
				tmp.T[i]=T[i]-obj.T[i];
			}
			return tmp; //zwracam
		}
	}
	void wynik();    //metoda wyswietlajaca obiekt
};

template<typename Typ>
K<Typ>::K(int roz)
{
	n=roz;
	T=new Typ[n];
	for(int i=0;i<n;i++)
	{
		cout<<"Podaj "<<i+1<<" wyraz: ";   //konstruktor, wczytujacy dane
		cin>>T[i];
	}
}

template<typename Typ>
K<Typ>::~K()
{
	//delete [] T;   //destruktor zwalnia pamiec, nad tym jeszcze pomysle
}


template<typename Typ>
void K<Typ>::wynik()
{
	for(int i=0;i<n;i++)
	{
		cout<<i+1<<" wyraz: "<<this->T[i]<<endl;      //metoda wypisujaca
	}
}

int main()
{
	K<int> b1(5), b2(3); //tworze obiekty
	K<int> b3;
	b1.wynik();
	b2.wynik();
	b3=b1-b2;  //odejmowanie
	b3.wynik();  //wypisanie
	system("PAUSE");
	return 0;
}
 

Problemy sprawiał destruktor, bez niego działa jak należy. Tylko, że tak jak myślałem jest wyciek pamięci. W operatorze odejmowania tworzę obiekt pomocniczy, on alokuje pamięć i nie ma jak jej zwolnić. Jakieś pomysły? :)

0

Brak konstruktora kopiującego, brak operatora przypisania, konstruktor domyślny nie inicjalizujący niczego.

0

Operator przypisania jest, bez tego new w bezargumentowym konstruktorze, krzyczy jak tworzę obiekt nie podając argumentu. Nad konstruktorem kopiującym aktualnie pracuję. Wydaje się działać, nie ma błędu Asertion Failed nawet jak działa destruktor, ale wycieki są nadal.

0

OK po problemie, kod dla innych jakby ktoś miał podobny problem. Należało dodać konstruktor kopiujący i przeciążyć operator =. Dzięki za pomoc! :)

 
#include <iostream>


using namespace std;


template<typename Typ>
class K
{
private:
	int n;    //wielkosc tablicy
	Typ *T;   //tablica
public:
	K()
	{
		T=new Typ;//bezargumentowy konstruktor, inicjalizuje wskaźnik
	}
	
	K(int roz);  //konstruktor
	~K();        //destruktor


	K &operator= (K<Typ> &ob) //operator przypisania
	{
		if(this!=&ob)
		{
			if(n!=ob.n)
			{
				delete [] T;
				n=ob.n;
				T=new Typ[ob.n];
			}
			for(int i=0;i<n;i++)
			{
				T[i]=ob.T[i];
			}
		}
		return *this;
	}

	//konstruktor kopiujacy
	K(const K<Typ>& ob)
	{
		if(this!=&ob)
		{
			if(n!=ob.n)
			{
			n=ob.n;
			T=new Typ[ob.n];
			}
		for(int i=0;i<n;i++)
		{
			T[i]=ob.T[i];
		}
		}
	}

	//operator odejmowania
	K operator-(const K<Typ> &obj)const
  {
	  int mniejszy;
	  if(n < obj.n)
		{
			mniejszy=n;
			K<Typ> tmp=*this;
		    for(int i=0;i<mniejszy;++i) 
			{
				tmp.T[i]=T[i]-obj.T[i];
			}	 
		     return tmp; 
		}
	  else 
		{
			mniejszy=obj.n;
			K<Typ> tmp=obj;
			for(int i=0;i<mniejszy;++i) 
			{
				tmp.T[i]=T[i]-obj.T[i];
				
			}
			return tmp; //zwracam
		}
	}
	void wynik();    //metoda wyswietlajaca obiekt
};


template<typename Typ>
K<Typ>::K(int roz)
{
	n=roz;
	T=new Typ[n];
	for(int i=0;i<n;i++)
	{
		cout<<"Podaj "<<i+1<<" wyraz: ";   //konstruktor, wczytujacy dane
		cin>>T[i];
	}
}

template<typename Typ>
K<Typ>::~K()
{
	delete [] T;   //destruktor zwalnia pamiec, nad tym jeszcze pomysle
}


template<typename Typ>
void K<Typ>::wynik()
{
	for(int i=0;i<n;i++)
	{
		cout<<i+1<<" wyraz: "<<T[i]<<endl;      //metoda wypisujaca
	}
}

int main()
{
	
	K<int> b1(5), b2(3); //tworze obiekty
	K<int> b3;
	b1.wynik();
	b2.wynik();
	b3=b1-b2;  //odejmowanie
	b3.wynik();  //wypisanie	
	system("PAUSE");
	return 0;
}
0

Musisz zaimplementować takie metody:

template<typename Typ>
class K
{
private:
	int n;    //wielkosc tablicy
	Typ *T;   //tablica
public:
	K(); // nie może być pusty!
	K(int roz);
        K(const K<Typ>& other);
	~K();

	K<Typ> operator-(const K<Typ>& other) const;
	K<Typ>& operator=(const K<Typ>& other);

	void wynik();
private:
        // to ci się może przydać:
        void zwolPam(); 
        void rezerPam();
};

Zwróć uwagę jak definiowana jest wartość zwracana!

0

Dzięki, chyba podobnie zrobiłem. Właśnie te wartości zwracane... kompilowałem to pod Visualem i działało. Próbuję teraz przez g++ i krzyczy:

  error: no matching function for call to ‘K<int>::operator=(K<int>)’
 note: candidates are: K<Typ>& K<Typ>::operator=(K<Typ>&) [with Typ = int]

Humm...

0

Ok, argument operator- nie był const i to powodowało błąd. Teraz już wszystko śmiga, dzięki wielkie raz jeszcze!

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