Przeciążanie operator=()

0

Witam wszystkich. Poczytałem Thinking in C++ Eckela i wg niego stworzenie
czegoś takiego to banał, ale nie dla mnie. Czemu to nie chce się skompilować?
Jak to rozwiązać? Używam BCB 6.0 Personal.

// w Unit1.h 

class TTest
{
 private:
  Variant vVal;
 public:
    TTest() { vVal = 0;};
   ~TTest() {};
    TTest& operator=(Variant cos) {vVal = cos; return *this;};
    Variant operator=(TTest& rt) { return rt.vVal;};
};

// w Unit1.cpp :

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TTest& t = * new TTest();
           t = 123; // tu operator=() łyka elegancko.
   
  Variant f = t; // po dodaniu do kodu tej lini - 
                 // [C++ Error] Unit1.cpp(27): E2034 Cannot convert 'TTest' to 'Variant'
  delete &t;
}

Drugi sposób:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TTest& t = * new TTest();
           t = 123;
   Variant f;
           f = t;
   // [C++ Error] Unit1.cpp(24): E2285 Could not find a match for 'Variant::operator =(TTest)'
  delete &t;
}
0

Operator przypisania definiuje co się dzieje podczas gdy napiszemy:obiekt naszej_klasy = cośtam;a ty próbujesz zrobić cośtam = obiekt naszej_klasy;Do tego potrzeba innego operatora - operatora rzutowania:

class TTest
{
 private:
  Variant vVal;
 public:
    TTest() { vVal = 0;};
   ~TTest() {};
    TTest& operator=(Variant cos) {vVal = cos; return *this;};
   operator Variant () { return vVal; } //operator rzutowania na typ Variant
};
0

OK. Dzięki wielkie. A jak rozwiązać problem (o ile to możliwe) żeby program sam umiał zdefiniować o jaką wartość chodzi:

class TTest
{
 private:
  Variant vVal;
 public:
    TTest() { vVal = 0;};
   ~TTest() {};
    TTest& operator=(Variant cos) {vVal = cos; return *this;};
   operator Variant () { return vVal; } //operator rzutowania na typ Variant
   operator String() {return String(vVal);}; 
};

a potem:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TTest& t = * new TTest();
           t = 123;
   Variant f;
           f = t;   // wyżuca coś z ambiguity between ...
   Caption = t; 
  delete &t;
}

Nie peamietam dokładnie treści [C++ Error] ale coś mówił o dwuznaczności użycia operatorów dla Variant i String.

0

TTest& t = * new TTest();
...
delete &t;

omfg.. nie wiem gdzie i kto taki pomysl Ci podsunal, ale mam cicha nadzieje ze ten ktos zalaczyl 1.5 strony A4 opisu dlaczego nigdy tak nie nalezy pisac..

a odpowiedz do Twojego pytania brzmi: dopisz rzutowanie ktore podpowie kompilatorowi o ktora 'konwersje' Ci chodzi, np. :
f = static_cast<String>(t)

0

Dzieki za odpowiedź. Co masz na myśli 1.5 strony A4..., jeżeli to jest nie OK, to jak powinienem to ująć żeby było "po polsku" dla kompuilatora. Co do rzutowania to mnie chodzi właśnie o to, jak zaoszczędzić sopie pisania w kodzie wykorzystującym moją klasę. Rozwiązanie mojego problemu to dorzucenie kilku funkcji do klasy o postaci np:

String toStr() {return String(vVal);}
int toInt() {return StrToInt(toStr);};
itp ...

a tego właśnie staram się uniknąć.
czy istnieje inne rozwiązanie tego problemu (patrz 2 posty wyżej).?
Z góry dziękuję za zaangażowanie...

0

Z tego co widzę próbujesz napisać na nowo Variant'a ale po co ?

0

No i mnie sie tak wczoraj wydało.
Może to banał ale próbuje dojść jak ONI to zrobili w VBA dla Excela gdzie odwołując sie do komórki arkusza:

...Range("A5") = 125

  cos As String

  cos = Range("A5")

nie trzeba odwoływać sie d o"Value".
Chcę zrobić sobie pod C++ cos w rodzaju servera arkuszy excelowskich do wymiany danych.

Czy da się jakoś to rozwiązać w twj mojej klasie?
Pozdrawiam.

PS. Z jakich źródeł czerpałeś wiedzę na temat operatorów bo w helpie BCB ani w swoich podręcznikach nie trafiłem na takie rozwiązanie.

0
zibicoder napisał(a)

PS. Z jakich źródeł czerpałeś wiedzę na temat operatorów
Ze świata :)

zibicoder napisał(a)

w helpie BCB ani w swoich podręcznikach nie trafiłem na takie rozwiązanie.
Wpisz w helpie Borlanda "operators" i wybierz poniżej w listboxie podkategorię "C++" (artykuł ma tytuł "C++ Operators"), będzie lista wszystkich operatorów.

//edit

A w VBA excela to chyba wszystko jako string idzie.

Dlaczego nie użyjesz po prostu Variant ?

0

Czy w Stringach w VBA tego nie wiem, sądziłem że to Variant'y są bo taka dowolność przypisywania.
A jak już szukam "łatwizny" w puźniejszym pisaniu kodu do dobrze by było wczytać vValue od razu do typu którym będę manipulował w C++.

Czy nie ma jakiegoś sposobu na przeciążenie tych:

operator String() {..};
operator Variant() {..};

chodzi o rozwiązanie tego wewnątrz klasy (o ile można to osiągnąć).

0

Witam
Mam problem chyba z operatorem przypisania. Piszę program mający wykonywać operacje na macierzach. Macierz jest reprezentowana prze zwykłą tablice dwuwymiarową. Zadeklarowałem między innymi konstruktor kopiujący i operator przypisania. Obydwa niby działają ale nie mogę zwrócić macierzy w funkcji.

Prgram kompiluje w Dev-C++

class Tab
{
	private:
		double** t;
		int n;           //wiersze
		int m;          //kolumny
	public:
                Tab();
		Tab(int N, int M);
		Tab(int N, int M, double** T);
		Tab(Tab & T);
		~Tab();
		Tab & operator=(Tab & T);
		int w();
		int k();
		double* operator[](int i);
};

i metody

Tab::Tab()
{
	t=0;
	n=m=0;
}
Tab::Tab(int N, int M)
	:n(N), m(M)
{
	t=new double*[n];
	for(int i=0; i<n; i++)
	{
		t[i]=new double[m];
		for(int j=0; j<m; j++)
			t[i][j]=0;
	}
}
Tab::Tab(int N, int M, double** T)
	:n(N), m(M)
{
	t=new double*[n];
	for(int i=0; i<n; i++)
	{
		t[i]=new double[m];
		for(int j=0; j<m; j++)
			t[i][j]=T[i][j];
	}
}
Tab::Tab(Tab & T)
	:n(T.w()), m(T.k())
{
	t=new double*[n];
	for(int i=0; i<n; i++)
	{
		t[i]=new double[m];
		for(int j=0; j<m; j++)
			t[i][j]=T[i][j];
	}
}
Tab::~Tab()
{
	for(int i=0; i<n; i++)
		delete[] t[i];
	delete[] t;
}
Tab  & Tab::operator=(Tab & T)
{
	for(int i=0; i<n; i++)
		delete[] t[i];
	delete[] t;
	n=T.w();
	m=T.k();
	t=new double*[n];
	for(int i=0; i<n; i++)
	{
		t[i]=new double[m];
		for(int j=0; j<m; j++)
			t[i][j]=T[i][j];
	}
	return *this;
}
int Tab::w()
{
	return n;
}
int Tab::k()
{
	return m;
}
double* Tab::operator[](int i)
{
	if(!stat)
		return 0;
	return t[i];
}

Jak nietrudno zauwarzyć na razie to robi nic

Tab f()
{
        return a(6, 7);
}

int main()
{
       Tab a(4, 5);         //to działa
       Tab b(a);             //to działa
       a=b;                   //to działa
       Tab c=f()            //to nie działa
}

Nie mam bladego pojęcia co tu może nie grać. Kompilator mówi mi ze22 "no match for 'operator=' in 'c = f()' że "candidates are: Tab& Tab::operator=(Tab&) "
Z góry bardzo dziekuję za wszystike odpowiedzi.

0

przerób operator= na pobierający const Tab&
a w związku z tym przerób niektóre metody, np

int w();
//zamień na
int w() const;

int Tab::w() const
{
        return n;
}
0

Ok. Chyba działa. Wielkie dzięki. Tyle że zostałem zmuszony zmodyfikować jedną z funkcji klasy następująco:

double* operator[](int i) const;
//zamiast double* operator[](int i);

//i
double* Tab::operator[](int i) const
{
	if(!stat)
		return 0;
	return t[i];
}

Czyli zwracam wskaźnik na tablicę, kompilator powinien się obrazić bo ten wskaźnik nie jest const. No ale jakoś to uszło.
Jednego jeszcze nie rozumiem: dlaczego to zaczeło działać?

0

Już tłumaczę :)
zwróć uwagę na swój operator:

Tab & operator=(Tab & T);

albo po prostu na funkcję:

void blabla(Tab & T);

cóż to za funkcja jest? Ano to jest funkcja, która pobiera argument przez & (referencję). Oznacza to, że funkcja może (albo nawet chce) modyfikować ten argument swój. Czy każdy argument można tak bezkarnie modyfikować? Ano nie każdy:

Tab zmienna;
const Tab stala_zmienna;

blabla(zmienna); // idzie
blabla(stala_zmienna); // nie idzie! nie można grzebać w obiekcie stałym!

A więc funkcja nie może pobierać obiektów stałych, niemodyfikowalnych. Czy ty jej taki argument dajesz? Ano dajesz. Bo okazuje się, że w C++ uważa się, że obiektów tymczasowych się nie modyfikuje. Są traktowane jako const właśnie. Czyli takie rzeczy nie przejdą:

// zwraca obiekt tymczasowy przez wartość
// taki wynik można czytać, kopiować, przepisać,
// ale do samego wyniku nie można pisać
Tab temp() { return Tab; } 

blabla( temp() ); // nie przejdzie
blabla( Tab() ); // podajemy tablicę stworzoną na miejscu - tymczasową, też nie pójdzie

Dobra, czyli zmieniamy na const Tab& - co znaczy, że bierzesz przez referencję, ale zobowiązujesz się nie grzebać w tym, co dostałeś.

Na koniec, co oznacza taka funkcja?

double* Tab::operator[](int i) const {
    return !stat ? 0 : t[i];
    }

Ano, ona nie nie znaczy, że wynik będzie const. To nasze const po deklaracji oznacza, że nie będziemy w tej metodzie (tutaj: operatorze) robić nic, co by nam zmieniło obiekt. Zwracamy wynik - ten wynik może być wykorzystany w niecnych celach, tego nikt nie obiecuje. Obiecujesz jedynie, że ty nie zrobić nic "złego" w celu zwrócenia wyniku. Tak swoją drogą, to jeszcze ze zwracanym wynikiem jest trochę niuansów (tzn czasem trzeba zwrócić const typ&, zamiast typ&) ale tutaj akurat masz czysto. Jakby się purysta czepiał: wynika to stąd, że twoja ostrożna constowa funkcja traktuje obiekt jako tylko-do-odczytu. I wszystkie składowe obiektu są tylko do czytania. Składowe - a więc na przykład twój wskaźnik double** t. Dokładnie zwróć uwagę, wskaźnik - ale to, na co on wskazuje, to już nie - z tym można robić wszystko, wolna wola. Dlatego możesz wskazywany blok pamięci zwrócić jako double* i nikt nie protestuje.

Późno, po podróży jestem ja, jak coś niejasno, mętnie, dziwnie, to drzeć się, jutro przed południem opiszę może systematyczniej.

0

Dziękuję bardzo za wyjasnienia, już wszystko rozumiem. Nie wiedziałem że obiekty tymczasowe są uważane za stałe.
Jeszcze raz bardzo diękuję.

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