Zwracane wartości przeładowanych operatorów

Zwracane wartości przeładowanych operatorów
N0
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 55
0

Czesc,

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

Kopiuj
 
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

_13th_Dragon
  • Rejestracja: dni
  • Ostatnio: dni
1

Po pierwsze:

Kopiuj
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:

Kopiuj
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.

Azarien
  • Rejestracja: dni
  • Ostatnio: dni
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ść.

N0
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 55
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ś

Kopiuj
return *this

a to przecież jest wskaźnik?

_13th_Dragon
  • Rejestracja: dni
  • Ostatnio: dni
1
Kopiuj
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ą.

Azarien
  • Rejestracja: dni
  • Ostatnio: dni
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.
N0
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 55
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:

Kopiuj
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

robcio
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Opole
  • Postów: 533
0

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

Kopiuj
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.

N0
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 55
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

N0
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 55
0

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

_13th_Dragon
  • Rejestracja: dni
  • Ostatnio: dni
1

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

N0
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 55
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

N0
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 55
0

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

Kopiuj
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?

N0
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 55
0

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

_13th_Dragon
  • Rejestracja: dni
  • Ostatnio: dni
0

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

N0
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 55
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?

Kopiuj
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;
}
//********************************************************************************
Kopiuj
*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?

_13th_Dragon
  • Rejestracja: dni
  • Ostatnio: dni
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.

N0
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 55
0

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

_13th_Dragon
  • Rejestracja: dni
  • Ostatnio: dni
1

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

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.