Stos - indeksowanie c++

0

Witam wszystkich. Mój problem polega na tym, iż chciałbym utworzyć dynamiczną tablicę dwuwymiarową z obiektów klasy szablonowej mianowicie w main() wpisuje:
(poniżej zamieszczę pełny kod źródłowy)

stos<int> www[2][2];
www[0][0] = 1;

wywala mi błąd:

int main()':
no match for 'operator=' in 'www[0][0] = 1'
candidates are: stos<int>& stos<int>::operator=(const stos<int>&)
)) < www[0][0]'

Przykład pochodzi z książki Jerzego Grębosza pod tytułem "Pasja c++".

Jak przerobić poniższy przykład, aby możliwe było utworzenie takiej tablicy dynamicznej dwuwymiarowej np. www[n][m] przy czym podajemy w trakcie działania programu "n" i "m".

#include <iostream>
using namespace std;

template <class typOBJ> class stos;
template <class typOBJ> ostream &  operator<<(ostream & stru, stos<typOBJ> & spis);

template <class typOBJ>
class stos{												
	typOBJ * tabl; 								
	int pojemnosc;
public:
	int ile_obiektow ;
	stos()		
 	{
		ile_obiektow = 0 ;
		pojemnosc = 10 ; 				/
		tabl = new typOBJ[pojemnosc] ;
	}

	~stos()											
 	{
 		delete [] tabl ;
 	}

	void push(typOBJ nowy);
	typOBJ pop();

	friend
	ostream &  operator<<  
		<typOBJ>     
		(ostream & stru, stos<typOBJ>& x);   

> 
   operator=<typOBJ>

private:
	int powieksz_rozmiar_stosu() ;
};

template <class typOBJ>
void stos<typOBJ>::push(typOBJ nowy) 
{
	if(ile_obiektow == pojemnosc)		 			
	{
		cout << "(stos sie zapelnil, rozszerzam sie)\n" ;
 		 				
	 	powieksz_rozmiar_stosu();
 		 	
	}
	tabl[ile_obiektow++] = nowy ;
}
/*************************************************************/
template <class typOBJ>
typOBJ stos<typOBJ>::pop()		
{
	if(ile_obiektow <= 0)
	{
 		cout << "\n*** Alarm, ze na stosie jest pusto!*** \n";
		return 0 ; 				
 	}
 	return( tabl[--ile_obiektow] );
}

template <class typOBJ>
int stos<typOBJ>::powieksz_rozmiar_stosu()		
{
	int dodatek = 10 ;
	typOBJ * nowa_tabl = new typOBJ[pojemnosc + dodatek];

	if(nowa_tabl == NULL) 			
 	{
		return 0 ; 					
 	}
 
 	for(int i = 0 ; i < ile_obiektow ; i++)
 	{
 		nowa_tabl[i] = tabl[i] ;
  	}
  	pojemnosc += dodatek ; 			
 	delete tabl ;					
 	tabl = nowa_tabl ;  	
	return 1 ;
}

template <class typOBJ>
ostream &  operator<<(ostream & stru, stos<typOBJ> & spis)
{
	for(int i = 0 ; i < spis.ile_obiektow ; i++)
	{
		stru << spis.tabl[i] << " " ;
	}
	stru << endl ;
	return stru ;
}

int main()
{
	stos<int> sss; 			 						
    
    
 	sss.push(0) ;
 	sss.push(1) ;
 	sss.push(2) ;
 	sss.push(3) ;
 	for(int i = 4 ; i < 24  ; i++) 			
 		sss.push(i) ;

 	cout << sss ;

 	int m = sss.pop() ;
 	int k = sss.pop() ;
 	cout << "zdjelismy ze stosu liczby m=" << m
 		<< " i k =" << k << endl ;

 	cout << "Kolejno zdejmujemy nastepne\n"  ;
	cout << sss.pop() << endl ;
	cout << sss.pop() << endl ;
	cout << sss.pop() << endl ;
 	while(sss.ile_obiektow)				
 	{
		cout << sss.pop() << " " ;
 	}
 	cout << "\nProbujemy zdjac jeszcze jedna\n" ;
 	cout << sss.pop() << " " ; 	     

 	cout << "\n-----------\nJeszcze raz cos ladujemy...\n" ;
 	for(int j = 0 ; j < 50 ; j++)sss.push(10*j);

 	stos<int> drugi ; 						
 	cout << "Przeladowujemy zdejmujac z pierwszego stosu\n"
 				"i ladujac na drugi\n" ;
 	for(int n = 0 ; n < 10 ; n++)
 	{
 		drugi.push( sss.pop()); 				
   	}
 	cout << "Oto kolejne zdejmowania z drugiego stosu:\n";
 	for(int p = 0 ; p < 7 ; p++)
 	{
 		cout << drugi.pop() << " " ;
 	}

	const char *slowo[] = { "Stolica","Nepalu","jest","Kathmandu"};

 	stos<const char*> zzz;							
 	for(int r = 0 ; r < 4 ; r++)
 		zzz.push(slowo[r]);

 	cout << "\nPrzy zdejmowaniu ze stosu czytamy\n" ;
 	for(int s = 0 ; s < 4 ; s++)
		cout << zzz.pop() << " " ;

    stos<int> www[2][2];
    www[0][0] = 1;
    cout<<"To jest moj stos: "<www[0][0];

system("pause");
return 0 ;
}
0
  1. Formatowanie kodu!
stos<int> www[2][2];
www[0][0] = 1; 

Ciekawe czy rozumiesz co w ten sposób robisz:

  1. Tworzymy dwuwymiarowa tablice stosów<int>
  2. Przypisujemy do stosu [0][0] liczbe całkowitą 1, a gdzie masz przeciążony operator przypisania dla int?? Kompilator wszystko podaje na tacy trzeba tylko to czytać O_o:

Powineneś zrobić tak:

www[0][0].push(1); // odkładamy na stos liczbe 1

No i oczywiscie ta cała klasa stos jest niekompletna gdyz powoduje problemy z pamiecią:

  1. Brak definicji poprawnego konstruktora kopiujacego - powinien wykonac tzw. deep coping, gdyz domyślny kk kopiuje zawartosc wskaznikow a nie dane przez niego wskazywane.
  2. Brak definicji operatora przypisania: powinen najpierw zwolnic stara pamiec stosu i zalokowac nową, po czym przypisac zawartosc przekazanego stosu do nowej pamieci.
0
xmoon napisał(a)
  1. Formatowanie kodu!
stos<int> www[2][2];
www[0][0] = 1; 

Ciekawe czy rozumiesz co w ten sposób robisz:

  1. Tworzymy dwuwymiarowa tablice stosów<int>
  2. Przypisujemy do stosu [0][0] liczbe całkowitą 1, a gdzie masz przeciążony operator przypisania dla int?? Kompilator wszystko podaje na tacy trzeba tylko to czytać O_o:

Powineneś zrobić tak:

www[0][0].push(1); // odkładamy na stos liczbe 1

No i oczywiscie ta cała klasa stos jest niekompletna gdyz powoduje problemy z pamiecią:

  1. Brak definicji poprawnego konstruktora kopiujacego - powinien wykonac tzw. deep coping, gdyz domyślny kk kopiuje zawartosc wskaznikow a nie dane przez niego wskazywane.
  2. Brak definicji operatora przypisania: powinen najpierw zwolnic stara pamiec stosu i zalokowac nową, po czym przypisac zawartosc przekazanego stosu do nowej pamieci.

Troszeczkę się pogubiłem w tym co napisałeś, mógłbyś napisać jak jak wyglądałby taki konstruktor oraz jak zdefiniować taki operator przypisania... Z góry dziekuje

A więc tak:

Domyslny Konstruktor kopiujacy kopiuje zawartosc wszystkich pol klasy np. w tym wypadku bedzie to m.in. wskaznik tab1. Nastepuje tutaj kopiowanie adresu wskazujacego nasze dane stosu:

stos<int> a;
a.push(1);
a.push(2);
stos<int> b(a); // obiekt b posiada ten sam wskaznik tab1, wiec cos jest nie tak....

Standardowy kk mozna przypuszczac ze wyglada tak:

stos::stos(const stos & s){
  tab1 = s.tab1; // kopiowanie adresu ale nie danych
  // ...
}

musimy stworzyc własny:

template <class T>
stos::stos(const stos & s){
  tab1 = new T[s.ile_obiektow]; // tworzymy pamiec na nowy stos
  // ...
  // Tutaj kopiujemy ze stosu s do nowej pamieci
  // ... 
}

Powinenes juz wiedziec o co chodzi, bez takiego konstruktora kopiowanie stosu byłoby nie mozliwe gdyz kazda kopia wskazywała by na ten sam obszar pamięci.

Co to operatora przypisania to standardowy moze wygladac tak:

stos & stos::operator=(const stos & s){
  if(*this == s) return *this;
  tab1 = s.tab1;
  // ...
}

Na pierwszy rzut oka nie ma nic podejrzanego ale co sie dzieje z pamiecia pod adresem tab1?? Inaczej mowiac gubimy ją, nie zwalniając jej przed przypisaniem s.tab1; Nasz op powienien wygladac tak:

stos & stos::operator=(const stos & s){
  if(*this == s) return *this; // sprawdzamy czy nie przypisuje samego siebie
  delete [] tab1; // zwalniamy pamiec
  tab1 = s.tab1; // teraz jest ok
  // ...
}

Mniej wiecej o to chodzi aby nie gubic alokowanej pamieci i nie powodowac jej wycieków.

Jeszcze mam uwage do operacji wejscia/wyjscia m.in. cout w metodach klasy, to troche utrudnia dalsza rozbudowe klasy, metody w tym przypadku powinny zwracac wartos logiczna np true - udało sie połozyc na stos, false - nie mozna połozyc stos pełny i wyswietlic info o błedzie juz w funkcji głównej, a nie "uzależniać" od tego klasę.

pozdro.

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