Zwracane wartości przeładowanych operatorów

0

Czesc,

mam pytanie;
chodzi mi o zwracanie rezultatu przeladowanych operatorow, np.:

 
CIntArray& CIntArray::operator=(const CIntArray& aTablica)

{

   // usuwamy naszą tablicę

   delete[] m_pnTablica;
 

   // alokujemy tyle pamięci, aby pomieścić przypisywaną tablicę

   m_uRozmiar = aTablica.m_uRozmiar;

   m_pnTablica = new int [m_uRozmiar];
 

   // kopiujemy tablicę

   memcpy (m_pnTablica, aTablica.m_pnTablica, m_uRozmiar * sizeof(int));

 
   // zwracamy wynik

   return *this;

}

Jak wytlumaczyc koniecznosc zwracania wskaznika na obiekt przy tym operatorze? Jak wytlumaczyc ze raz zwracamy wskaznik a raz caly obiekt w zaleznosci od operatora? Nie moge wylapac tej roznicy.

Moze tak postawie pytanie: Co sie dzieje ze wskaznikiem przekazywanym na koncu? Bo przeciez wszelkie potrzebne operacje dokonuja sie w ciele funkcji, wiec dlaczego nie mogla by ona nic nie zwracac? void ?

Jakby mi ktos to rozjasnil to bede wdzieczny, pozdrawiam

1

Po pierwsze:

CIntArray &CIntArray::operator=(const CIntArray &aTablica)
  {
   if(this!=&aTablica) // bez tego a=a; zrobi kuku
     {
      if(m_uRozmiar!=aTablica.m_uRozmiar) // nie ma co zwalniać i przydzielać jeżeli mamy ten sam rozmiar
        {
         delete[] m_pnTablica;
         m_uRozmiar=aTablica.m_uRozmiar;
         m_pnTablica=new int[m_uRozmiar];
        }
      memcpy(m_pnTablica,aTablica.m_pnTablica,m_uRozmiar*sizeof(int));
     }
   return *this;
  }

Po drugie: żaden z operatorów nie powinien zwracać wskaźnika, powinien zwracać wartość lub referencję.

Po trzecie: nie ma konieczności zwracania referencji przez ten operator, możesz zrobić yo tak:

void CIntArray::operator=(const CIntArray &aTablica)

ale w tym przypadku wyrażenie: a=b=c; - nie skompiluje się.

Po czwarte: zasada jest prosta jeżeli obiekt się zmienił podczas działania operatora i ta zmiana jest wynikiem to można zwrócić referencje na siebie.

1

Jak wytlumaczyc ze raz zwracamy wskaznik a raz caly obiekt w zaleznosci od operatora?
Zależy od konkretnego operatora.
Operatory przypisania i przesunięcia powinny zwracać referencję. Operatory arytmetyczne – wartość.

0

oo dzięki kumam, prawie,

pisząc o wskaźniku miałem na myśli referencje, właśnie tylko pewnie mam tu jakąś lukę. Bo przecież referencja to tak na dobra sprawę jest wskaźnik? Ale skoro by tak było to gdzie jest ta różnica w zwracaniu referencji a wskaźnika? Piszesz, ze powinno się zwracać referencje, a w kodzie wysłałeś

return *this

a to przecież jest wskaźnik?

1
this - wskaźnik - CIntArray*
*this - referencja - CIntArray&

Tak samo jak zawartość butelki jest piwem, nie butelką.
Albo zawartość czaszki jest mózgiem a nie kością.

1
  1. referencja to taki niejawny wskaźnik, bo do obiektu odwołuje się jak do obiektu (a nie jak do wskaźnika), używa operatora . a nie -> itp.
  2. referencja wewnętrznie jest realizowana jako wskaźnik, ale teoretycznie wcale nie musi.
  3. this jest wskaźnikiem, *this jest wskazywanym przez wskaźnik obiektem. a składnia referencji jest taka jak obiektu, a nie taka jak wskaźnika.
0

dzieki za odpowiedzi,

niestety dalej gdzies mam blad w kodziem, ktorego nie moge zlokalizowac. Mam program obslugujacy klase Tablice, ktora przechowuje dynamiczna tablice liczb double.

Obiekty sa grupowane w tablicy baza[10] , jest to tablica wskaznikow na obiekty klas. Niestety mam problem z wykonaniem dodania dwoch tablic, napisalem konsutrktor kopiujacy, przeciazylem operatory + i - , ale podczas dodawania nastepuje naruszenie pamieci, w wyniku tworzy sie wyzerowana tablica i jedna w ktorej nic nie ma. Czyli powstaja dwie, a powinna jedna wynikowa. Jakbyscie mogli zerknac:

case 5:
		{
			system("CLS");
			cout << "Dodamy do siebie dwie pierwsze tablice i zapiszemy w nowej\n";
			cout << "Uzywamy przeladowanego operatora '+'\n\n";
			int rA = baza[0]->rozmiar();
			int rB = baza[1]->rozmiar();
			dodaj_tablice((rA > rB) ? rA : rB); 
			*baza[pnt-1] = *baza[0] + *baza[1];
			break;
                }
//********************************************************************************
void dodaj_tablice(int n)
{
	int m = Tablica::ilosc;
	baza[m] = new Tablica(n); 
	if(baza[m] == NULL) {cout << "\n\tBrak pamieci\n";}
}
//********************************************************************************

**//Konstruktory i Destruktor:**

//inicjalizowanie zmiennej statycznej klasy, licznika obiektow
//********************************************************************************
int Tablica::ilosc = 0; 
//********************************************************************************
Tablica::Tablica()
{
	ilosc++;
	id = Tablica::ilosc;
	nazwa = "Tablica";
	nazwa += id;		
}
//********************************************************************************
Tablica::Tablica(int rozmiar) : n(rozmiar)
{
	ilosc++;
	id = Tablica::ilosc;
	tab = new double[n];
	wyzeruj();
	nazwa = "Tablica";
	nazwa += id;			
}
//********************************************************************************
Tablica::Tablica(int rozmiar, char *name) : n(rozmiar)
{
	ilosc++;
	id = Tablica::ilosc;
	tab = new double[n];
	wyzeruj();
	nazwa = name;
}
//********************************************************************************
Tablica::Tablica(const Tablica& kTablica) : n(kTablica.n)
{
	ilosc++;
	// pobieramy rozmiar kopiowanej tablicy
	tab = new double(n);
	// kopiujemy tablice 
	memcpy(tab, kTablica.tab, n*sizeof(double));
	srd = kTablica.srd;
	id = Tablica::ilosc;
	nazwa = "Tablica";
	nazwa += id;		
}
//********************************************************************************
Tablica::~Tablica()
{
	cout << "\nDESTRUKOR: " << this->nazwa << endl ; 
	ilosc--; 
	delete[] tab;
	tab = NULL;
}
//********************************************************************************				

**// Przeciazone operatory::**

//********************************************************************************
Tablica Tablica::operator+(const Tablica& b)
{
	int rB = b.rozmiar();
	int rA = rozmiar();
	int k = (rA > rB) ? rA : rB;  //r --> rozmiar wiekszej z dodawanych tablic 
	Tablica temp(k);
	for(int i=0; i<k ; i++)
	{
		temp.tab[i] = ((i >= rA) ? 0 : tab[i]) + ((i >= rB) ? 0 : b.tab[i]); 
	}
	temp.srednia();
	return temp;
}
//********************************************************************************
Tablica& Tablica::operator=(const Tablica& obiekt)
{
	if(&obiekt == this) return *this;
	if(obiekt.n != n)
	{
		delete[] tab;
		n = obiekt.n;
		tab = new double[n];
	}
	
	memcpy(tab, obiekt.tab, n*sizeof(double));
	srd = obiekt.srd;
	return *this;
}
//********************************************************************************

**tablica.h**

#include <string>

#pragma once
class Tablica
{ 
	std::string nazwa;
	double *tab;
	double srd; //srednia elementow
	int id;
	int n; //rozmiar tablicy
	
	
public:
 
	Tablica();
	Tablica(int);
	Tablica(int, char*);
	Tablica(const Tablica&);
	~Tablica(); 
		
	void wypelnij();
	void wyzeruj();
	void wyswietl(int = 1, int = 0) const;
	void insert_sort();
	void srednia();
	int rozmiar() const {return n;};
	double* adres() const {return tab;};
	size_t ilosc_bajtow() const;

	static int ilosc; //licznik obiektow
	static int str_lngt;

	Tablica operator+(const Tablica&);
	Tablica& operator=(const Tablica&);
	
};

Całe pliki:
plik main.cpp --> http://pastebin.com/0RLZnbKh
plik tablice.cpp --> http://pastebin.com/Z1JWiScY

0

na pierwszy rzut oka masz coś nie tak w tej linijce:

int k = (rA > rB) ? rA : rB;  //r --> rozmiar wiekszej z dodawanych tablic

załóżmy że wartość rA wynosi 5 a wartość rB wynosi 3 to rozmiar tablicy do zsumowania będzie wynosił 5 a powinien wynosić 8. Tak jak ty zrobiłeś to nie pomieścisz wszystkich elementów.

0

no ale sumuje ze soba odpowiadajace pozycje tablicy, czyli A.tab[0] + B.tab[0], A.tab[1] + B.tab[1] , tak wiec tutaj nie ma bledu, pomozcie plz przez ten blad nie moge sie ruszyc do przodu yhh

0

Debugger podpowiada : "Invalid allocation size:48389893...."

1

Błąd w trzecim wierszu konstruktora kopiującego new double(n) nie jest tym samym co new double[n]

0

faktycznie ale plama, niestety dalej jest problem, teraz troche innej natury >> "Access violation reading location"

wrzucilem pliki projektu -> http://speedy.sh/kDxs3/program-klasa.zip

0

ok, powoli ogarniam dzialanie debuggera, obecnie zlokalizowalem punkt krytyczny, jednak nie moge dojsc co idzie nie tak

Tablica& Tablica::operator+(const Tablica& b)
{
	int rB = b.rozmiar();
	int rA = rozmiar();
	int k = (rA > rB) ? rA : rB;  //k --> rozmiar wiekszej z dodawanych tablic 
	static Tablica temp(k);
	for(int i=0; i<k ; i++)
	{
		temp.tab[i] = ((i >= rA) ? 0 : tab[i]) + ((i >= rB) ? 0 : b.tab[i]); 
	}
	temp.srednia();
	return temp;
}
//********************************************************************************
Tablica& Tablica::operator=(const Tablica& obiekt)
{
	if(&obiekt == this) return *this;
	n = obiekt.rozmiar(); // <------ W tym miejscu program sie wychacza
	if(obiekt.n != n)
	{
		delete[] tab;
		tab = new double[n];
	}
	memcpy(adres(), obiekt.adres(), n*sizeof(double));
	srd = obiekt.srd;
	return *this;
}

wiec program sie wysypuje w miejscu w ktorym operator = chce pobrac przez referencje obiekt zwracany przez wynik sumy czyli: (*baza[0] + *baza[1])

Czyli na moje oko, to wyglada tak jakby obiekt zwracany przez operator + byl kasowany po zakonczeniu funkcji operatora. No bo przeciez obiekt temp jest tworzony wewnatrz funkcji przeladowania, a wiec jego destruktor jest wykonywany po upuszczeniu zakresu funkcji, mam racje?? Jezeli tak to w jaki sposob jest ten obiekt zwracany poprzez return ?? Co jest zwracane i w jaki sposob?

Mozecie mi to jeszcze rozjasnic?

0

Ok sprawa sie wyjasnila, zmienna byla zle wyliczona pod ktora zapisywany byl wskaznik nowo tworzonego obiektu (pnt)

0

static Tablica temp(k); - to jest bardzo źle. Konstruktor odpali się tylko raz

0

to byla tylko proba zeby cos ruszyc, blad byl gdzie indziej i static szybko wywalilem. Tablica byla zle zaindeksowana.....

Natomiast mam pytanie, bo jak podgladam program, to najpierw wywolywany jest konstruktor kopiujacy a dopiero pozniej operator przypisania. A podobno kopiujacy uruchamia sie tylko w momencie inicjalizacji nowego obiektu? Tutaj tego nie mam wiec dlaczego sie uruchamia? Przeciez sam operator przypisania powinien tu calkowicie wystarczyc?

Tablica::Tablica(const Tablica& kTablica) : n(kTablica.rozmiar())
{
	ilosc++;
	tab = new double[n];
	memcpy(tab, kTablica.tab, n*sizeof(double));
	srd = kTablica.srd;
	
	id = Tablica::ilosc;
	nazwa = "Tablica ";
	ostringstream id_temp;
	id_temp << id;
	nazwa.append(id_temp.str());
	cout << "\nKonstruktor kopiujacy " << nazwa << endl;
}
//********************************************************************************
Tablica& Tablica::operator+(const Tablica& b)
{
	int rB = b.rozmiar();
	int rA = rozmiar();
	int k = (rA > rB) ? rA : rB;  //k -> rozmiar wiekszej z tablic 
	Tablica temp(k);
	for(int i=0; i<k ; i++)
	{
		temp.tab[i] = ((i >= rA) ? 0 : tab[i]) + ((i >= rB) ? 0 : b.tab[i]); 
	}
	temp.srednia();
	return temp;
}
//********************************************************************************
Tablica& Tablica::operator=(const Tablica& obiekt)
{
	if(&obiekt == this) return *this;
	n = obiekt.rozmiar();
	if(obiekt.n != n)
	{
		delete[] tab;
		tab = new double[n];
	}
	memcpy(adres(), obiekt.adres(), n*sizeof(double));
	srd = obiekt.srd;
	return *this;
}
//********************************************************************************
*baza[pnt-1] = (*baza[0] + *baza[1]);

W tym momencie odpalaja mi sie az 3 konstruktory, jeden docelowy (baza[]), jeden tymczasowy wewnatrz operator + i na koniec kopiujacy, dwa ostatnie sa niszczone i jest okey. Tylko po co ten kopiujacy?

0

Jesteś pewien że operator + wygląda u ciebie dokładnie tak jak podałeś wyżej. Jeżeli tak to jest to błąd który ci odbije się wywracaniem się programu. Operator + musi zwrócić obiekt, nie referencje.

0

tam nie ma referencji, hmm kopiowalem z innego miejsca, musialem tam miec zla wersje. Ponawiam pytanie w takim razie

1

Aby zwrócić wartość z return temp; w operatorze + potrzebny konstruktor kopiujący.

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