Obiekty stałe i konstruktor kopiujący

0

Witam,

używam Qt Creator w Linuksie.

Chcę napisać przykładowy program, który będzie używał klasy ze zdefiniowanymi stałymi a, b, c oraz z konstruktorem kopiującym.

Napisałem taki oto program, który wywala błędy. Co zrobiłem nie tak? A może to błąd kompilatora (choć to szansa 1 na 1E6)?
Według mnie pierwszy z kodów jest logicznie bardziej poprawny. Ale żadna z wersji nie działa.

#include <iostream>
using namespace std;
class Trojmian
{
    const double a, b, c;   double x;
public:
    Trojmian(double ax, double bx, double cx, double xx = 0.0):
        a(ax), b(bx), c(cx) { x = xx; }
    Trojmian(Trojmian &t) { x = t.x; }
    void wyswietl(void) { cout << a << b << c << x; }
};

int main(void)
{
  Trojmian t1(1, 0, -1), t2(1, 0, 0);
  t1 = t2;
  return 0;
}

Próbowałem też tak, ale błąd pojawiał się po wstawieniu instrukcji:

t1 = t2; // a o tę instrukcję najbardziej mi chodzi
#include <iostream>
using namespace std;
class Trojmian
{
    const double a, b, c;   double x;
public:
    Trojmian(double ax, double bx, double cx, double xx = 0.0):
        a(ax), b(bx), c(cx) { x = xx; }
    Trojmian(Trojmian &t): a(ax), b(bx), c(cx) { x = t.x; }
    void wyswietl(void) { cout << a << b << c << x; }
};

int main(void)
{
  Trojmian t1(1, 0, -1), t2(1, 0, 0);
  t1 = t2; // tutaj ta instrukcja powoduje błąd
  return 0;
}
1

Po co Ci ten const przy składnikach klasy? Przecież to nie ma sensu.

Żeby to działało musiałbyś przeciążyć operator=, ale nie możesz zmienić w nim stałych składników. Ta klasa nie ma więc sensu w tym kształcie.

0

Poprawnie będzie tak:

#include <iostream>
using namespace std;

class Trojmian
  {
   const double a, b, c;   double x;
   public:
   Trojmian(double ax,double bx,double cx,double xx=0.0):
        a(ax), b(bx), c(cx) { x = xx; }
   Trojmian(Trojmian &t): a(t.a), b(t.b), c(t.c) { x = t.x; }
   void wyswietl(void) { cout << a << b << c << x; }
   Trojmian &operator=(Trojmian &t)
     {
      const_cast<double&>(a)=t.a; // działa na 4-ch kompilatorach ale standard mówi - nieprzewidywalne zachowanie
      const_cast<double&>(b)=t.b; // jw
      const_cast<double&>(c)=t.c; // jw
      x=t.x;
      return *this;
     }
  };
 
int main(void)
  {
   Trojmian t1(1, 0, -1), t2(1, 0, 0);
   t1 = t2; // tutaj ta instrukcja powoduje błąd
   return 0;
  }

Nie jest to koszerne rozwiązanie, może zastanów się nad jednym z:

  1. zrezygnować z przypisywania: t1 = t2
  2. zrezygnować z const przy a,b,c
0

Faktycznie. Zapomniałem o const_cast. Ale zrezygnuję z tego kodu, bo jest niepoprawny.

To miało być w celach edukacyjnych (jestem nauczycielem). chciałem pokazać, że stałe można inicjalizować tylko za pomocą listy inicjalizacyjnej oraz jak działa konstruktor kopiujący (w jednym przykładzie).

A może ktoś ma lepszy pomysł na taki przykład?

0

Jak musisz mieć stałą w obiekcie to operator = musi ją pominąć. Dobrym przykładem jest punkt który wewnątrz ma współrzędne x,y oraz stałą bool która mówi jedynie o sposobie zadania współrzędnych w konstruktorze oraz sposób ich wprowadzenia cin>> oraz wyświetlenia cout<<. Sposób w sensie kartezjańskie czy biegunowe. Owszem nie jest najlepszy przykład w sensie OOP ale ten przykład właśnie pokazuje sens pomijania takiej stałej.

1

Ale zrezygnuję z tego kodu, bo jest niepoprawny.
Wywal po prostu to const z pól klasy.
Bo stałe pola i operator przypisania wzajemnie sobie przeczą.

A może ktoś ma lepszy pomysł na taki przykład?
Jakaś klasa, która w konstruktorze przydziela pamięć przez new, a w destruktorze zwalnia.

class Foobar
{
  int *ptr;
  public:
      Foobar() { ptr = new int[10]; }
      ~Foobar() { delete[] ptr; }
};

Zadanie: dorobić konstruktor kopiujący i operator przypisania.

Zadanie z gwiazdką: dorobić konstruktor przesuwający i operator przesunięcia.

0

Cały problem polega na podejściu do nauczani języka programowania: tu macie taki feature języka, wymyślcie(lę) sobie do niego przykład.
Na tym forum pojawia się sporo kwiatków wynikającego z takiego podejście do nauczania i to jest jeden z nich.

0

Co do tego kodu z Trojmianem, ja bym zrobił go tak:

#include <iostream>
using namespace std;
class Trojmian
{
	double a, b, c, x;
    public:
	Trojmian(double ax, double bx, double cx, double xx = 0.0)
		: a(ax)
		, b(bx)
		, c(cx)
		, x(xx)
	{}

	friend ostream& operator << (ostream &out, const Trojmian &tr);
};

ostream& operator << (ostream &out, const Trojmian &tr)
{
	return out << ' ' << tr.a << ' ' << tr.b << ' ' << tr.c << ' ' << tr.x;
}
 
int main(void)
{
	Trojmian t1(1, 0, -1), t2(1, 0, 0);
	cout << t1 << endl;
	cout << t2 << endl;
  
	t1 = t2;
	cout << t1 << endl;
	cout << t2 << endl;
	return 0;
}

Jak widać konstruktora czy operatora kopiującego wcale w tym przypadku nie potrzeba.
Dodatkowo odpowiedni operator dla cout, zamiast metody wyswietl.

0

Wg mnie jeżeli już ma by klasa trójmian to nie powinna zawiera tego x, czyli coś na kształt:

#include <iostream>
#include <iostream>
using namespace std;

struct Trojmian
  {
   double a, b, c;
   Trojmian(double a,double b,double c):a(a),b(b),c(c) {}
   ostream &prn(ostream &s)const;
   double operator()(double x) { return (a*x+b)*x+c; }
  };
inline ostream &operator<<(ostream &s,const Trojmian &T) { return T.prn(s); }

ostream &Trojmian::prn(ostream &s)const
  {
   s.setf(ios::showpos);
   if(a) { if(a==-1) s<<"-"; else if(a!=1) s<<a; else ; s<<"x^2"; }
   if(b) { if(b==-1) s<<"-"; else if(b!=1) s<<b; else if(a) s<<"+"; s<<b<<"x"; }
   if(c||((!a)&&(!b))) s<<c;   
   s.unsetf(ios::showpos);
   return s;
  }
 
int main(void)
  {
   Trojmian t1(1, 0, -1),t2(1, 0, 0);
   cout<<"t1="<<t1<<" t1(2)="<<t1(2)<<" t1(5)="<<t1(5)<<endl;
   t1.b=-2;
   cout<<"t1="<<t1<<" t1(2)="<<t1(2)<<" t1(5)="<<t1(5)<<endl;
   cout<<"t2="<<t2<<" t2(2)="<<t2(2)<<" t2(5)="<<t2(5)<<endl;
   t1 = t2;
   cout<<"t1="<<t1<<endl;
   cout<<"t2="<<t2<<endl;
   return 0;
  }

Ba wtedy nie boimy się dowolnych wartości a,b,c więc są jak najbardziej publiczne.
Wartość x podajemy jedynie dla obliczenia wartości trójmianu w konkretnym punkcie.

0
Azarien napisał(a):

Wywal po prostu to const z pól klasy.

I tak właśnie zrobiłem :-)

Dzięki wszystkim za odzew. Tym którzy najbardziej pomogli - kliknąłem.

Właściwie to przyszedł mi do głowy jeszcze jeden pomysł, ale to w osobnym wątku (chodzi o zweryfikowanie moich materiałów).

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