klasa romb - ustalenie hierarchii dziedziczenia

0

witam potrzebuje pomocy jak poprawnie zrobić klasę romb
ogólnie chodzi o to żeby dziedzicząc z klasy figura i pewnie prostokąt stworzyć figurę romb
pozdrawiam Marcin

// UserCode
// w tym pliku umieść swój kod

#include "Ekran.h"
#include "Figura.h"
#include "ListaFigur.h"
#include <math.h>

/* klasa EKRAN posiada następującą funkcjonalność:

void UstawPoz( int x, int y ); // ustawia bieżąca pozycję pędzla
void LiniaDo( int x, int y ); // rysuje linię z bieżącej pozycji pędzla do wskazanej pozycji
void RysujElipse( int left, int top, int right, int bottom ); // rysuje elipsę wpisaną w prostokąt o podanych współrzędnych

void UstawSzerokoscPedzla( int pikseli ); // ustawia szerokość pędzla (w pikselach)
void UstawKolorPedzla( int R, int G, int B ); // ustawia kolor pędzla
void UstawKolorPedzla( Koror& kolor ); // ustawia kolor pędzla
*/


class Prostokat : public Figura {
protected:
int cx, cy; // szer i wys.
public:
Prostokat(int x=0, int y=0, int szer=0, int wys=0, Kolor& kolor) : Figura(x,y,kolor) {
cx = szer; cy = wys;
};

virtual void Rysuj( Ekran& ekran ) {
ekran.UstawKolorPedzla( this->kolor );
ekran.UstawPoz( x, y );
ekran.LiniaDo( x+cx, y );
ekran.LiniaDo( x+cx, y+cy );
ekran.LiniaDo( x, y+cy );
ekran.LiniaDo( x, y );
};

virtual bool CzyToJa( int pozX, int pozY ) {
return x <= pozX && pozX <= x + cx && y <= pozY && pozY <= y + cy;
};

virtual void Obroc() {
int tmp = cx;
cx = cy;
cy = tmp;
};
};

class Kolo : public Figura {
private :
int promien;

public:
Kolo (int nX, int nY, int nP, Kolor& kolor) : Figura(nX,nY,kolor) {
promien = nP;
};

virtual void Rysuj( Ekran& ekran ) {
ekran.RysujElipse(x-promien, y-promien,x+promien,y+promien);
ekran.UstawKolorPedzla( this->kolor );
ekran.UstawPoz( x, y );


};



virtual bool CzyToJa(int x, int y) {};

};

class Romb : public Figura {
protected:
int cx, cy; // szer i wys.
public:
Romb(int x=0, int y=0, int szer=0, int wys=0, Kolor& kolor) : Figura(x,y,kolor) {
cx = szer; cy = wys;
};

virtual void Rysuj( Ekran& ekran ) {
ekran.UstawKolorPedzla( this->kolor );
ekran.UstawPoz( x, y);
ekran.LiniaDo( x+cx, y);
ekran.LiniaDo( x+cx, y+cy);
ekran.LiniaDo( x, y+cy);
ekran.LiniaDo( x, y);
};

virtual bool CzyToJa( int pozX, int pozY ) {
return x <= pozX && pozX <= x + cx && y <= pozY && pozY <= y + cy;
};

virtual void Obroc() {
int tmp = cx;
cx = cy;
cy = tmp;
};
};



void Ekran::Inicjalizacja() {
Kolor red(255,0,0), green(0,255,0), blue(0,0,255), yellow(255,255,0); // kolory podstawowe
//DodajFigure( new Kolo( 10, 10, 100, blue ) );
DodajFigure( new Prostokat( 10, 10, 100, 100, blue ) );
DodajFigure( new Romb( 50, 50, 100, 100, blue ) );

};
0

Romb != Prostokąt (o dziedziczeniu z prostokąta zapomnij)
A klasy figura to nie łaska pokazać?

0

Ale specyficzny prostokąt, kwadrat, jest rombem. Wg mnie po figura powinieneś dziedziczyć koło i trapez, po którym równoległobok, i po nim dopiero romb.

A dokładniej:

  • figura
    -- 1 wierzchołkowe
    -- 2 wierzchołkowe
    -- 3 wierzchołkowe
    -- n wierzchołkowe

A dla prostoty:

  • figura
    -- punkt
    -- linia
    -- trojkat
    --- jakieś specyficzne wielokąty
    -- czworokąt
    --- trapez
    ---- równoległobok
    itd
0

Jest to tak samo idziotyczne jak dziedziczenie kwadratu z prostokąta... co z tego, że jedno jest szczególnym przypadkiem drugiego, skoror w kodzie mogą wyjść jakieś głupoty...

Dla przykładu:

class prostokat
{
public:
    prostokat(){};
    unsigned int wys, szer;
    void ustawwys(unsigned int nwys)
           {
           wys = nwys;
           };
    void ustawszer(unsigned int nszer)
           {
           szer = nszer;
           };
    void wypiszpole()
           {
           cout<<wys*szer<<"\n";
           }
};

class kwadrat: public prostokat
{
public:
     kwadrat(){};
};

Teraz pomyśl, jakie metody i zmienne będzie zawierać klasa kwadrat, i co się stanie, jeśli gdzieś w kodzie wywołasz kwadrat::wypiszpole().

Dziedziczenie to potężne narzędzie, ale nie można stosować go pochopnie i gdzie popadnie.
Zasadniczo powinno się przy nim kierować dwoma zasadami:

  1. Dziedziczenie jest prawidłowe, kiedy pochodna może bez większych problemów zastąpić klasę, z której dziedziczyliśmy.
  2. Dziedziczenie jest prawidłowe, kiedy zawartość klasy dziedziczonej ma sens w klasie pochodnej.
0
Its not me napisał(a)

Jest to tak samo idziotyczne jak dziedziczenie kwadratu z prostokąta... co z tego, że jedno jest szczególnym przypadkiem drugiego, skoror w kodzie mogą wyjść jakieś głupoty...
...
Teraz pomyśl, jakie metody i zmienne będzie zawierać klasa kwadrat, i co się stanie, jeśli gdzieś w kodzie wywołasz kwadrat::wypiszpole().

erm.. z caly szacunkiem dla przedmowcy, ale masz na mysli implementacje wypiszpole (tzn. jako SZEROKOSC * WYSOKOSC) ? czy masz jedynie na mysli to, ze w/w kod nie jest calkiem prawidlowy? w pierwszym wypadku cofnij sie do geometrii z zakresu szkoly podstawowej gdyz tak sie sklada ze jest to prawda dla kazdego rownolegloboku, a w drugim zwaz, ze... to ze kod jest bledny nie jest winą dziedziczenia, ale bledu procesu myslowego implementatora (->Ciebie). Kwadrat jak najbardziej powinien dziedziczyc po prostokącie, ale powinien nadpisac metody ustaw szer/wys -- ktore zreszta powinny byc wirtualne od samego poczatku -- i w kwadracie ich implementacja powinna wygladac m/wiecej tak:

void kwadrat::ustawwys(unsigned int nwys)
{
    prostokat::ustawwys(nwys);
    prostokat::ustawszer(nwys);
};
void kwadrat::ustawszer(unsigned int nszer)
{
    prostokat::ustawwys(nszer);
    prostokat::ustawszer(nszer);
};
0

@Quet~
Ale jaki jest sens nadpisywania CAŁEJ zawartości klasy? W moim przykładzie wyraźnie widać, że aby klasa kwadrat działała poprawnie, należy przykryć wszystkie metody, a nie ma to sensu - w końcu kwadrat ma wysokość i szerokość tylko na poziomie podstawówki, potem jest krawędź ;] Chodzi o to, że w tym przypadku lepiej jest dziedziczyć z figury i zimplementować dwie nowe funkcje (które notabene robią zupełnie co innego, niż te w prostokącie), niż bawić się w przykrywanie 3 metod (a mogłoby ich być znacznie więcej, gbyby na przykład dodać wypisywanie obwodu, przękątnej itd)
Z matematycznego punkty widzenia kwadrat jest szczególnym przypadkiem prostokąta, ale z programistycznego taki zapis jest całkowitym bezsensem i zwiększa nakład pracy programisty, nie mówiąc już o tym, że zużycie pamięci przez kwadrat dziedziczony z prostokąta byłoby większe niż całkiem nowej klasy i choć w tym przypadku byłaby to całkiem niewielka różnica, to w większych projektach moglibyśmy na tym stracić wiele cennych mb :)
Dziedziczenie ma ułatwiać programistom życie, nie je komplikować.

0

Z matematycznego punkty widzenia kwadrat jest szczególnym przypadkiem prostokąta, ale z programistycznego taki zapis jest całkowitym bezsensem

przede wszystkim, dziedziczenie i OO polega na odwzorowaniu reczywistego problemu na język. Obiekty i relacje między mają być takie, jakie są "problemie" i to rzeczywistość / model powinien mieć pierwszeństwo przy tworzeniu hierarchii. Implementacja powinna mieć marginalny wpływ na strukturę projektu (np interfejsy, relacje dziedziczenia itd).

Twój przypadek kwadratu i prostokąta jest tego najlepszym przykładem, jest również przykładem tego, że w geometrii masz braki ;) jeśli piszesz, że

lepiej jest dziedziczyć z figury i zimplementować dwie nowe funkcje (które notabene robią zupełnie co innego, niż te w prostokącie), niż bawić się w przykrywanie 3 metod (a mogłoby ich być znacznie więcej, gbyby na przykład dodać wypisywanie obwodu, przękątnej itd)

W kwadracie należy jedynie rozszerzyć dwie funkcje (nawet nie zmienić!), tak jak quetzalcoatl podał (bo przecież w kwadracie ich działanie jest identyczne, tylko dodają od siebie nową cechę: pilnować, żeby szer==wys). Reszta działa prawidłowo z miejsca.

A tak swoją drogą, to można napisać dobre ogólne metody liczenia obwodu, przekątnych, pola itd na poziomie dowolnego czworoboku (a nawet N-boku), jeśli zdefiniujemy go za pomocą 4 (albo N) punktów, a reszta klas dziedziczących (prostokąt, kwadrat, równoległobok) będzie nakładać na te punkty jedynie ograniczenia, co sprowadzi się do tego, że metody setPunkt(int nr_punktu, const Punkt& value) będą pilnować spójności , albo przesuwając inne wierzchołki albo ładując radośnie wyjątkami. Metoda const Punkt& getPunkt(int nr_punktu) mile widziana by była też.

Klasy pochodne oprócz rozszerzenia setPunkt o nowe kryteria mogłyby dodawać metody-ułatwiacze w stylu: setWysokosc, setSzerokosc, setBok, setPodstawa, setLewyGornyRog ;)

Zysk:

  • idealna, matematyczna hierarchia (nie wymyślaj nowej "wydajniejszej pamięciowo") matematyki
  • każda nowa figura zawiera tylko kod pilnujący "charakterystycznych cech"
  • najważniejsze: uogólnione funkcje (np skalujące, obracające) będą mogły czytać bezpośrednio punkty i transformować. W końcu po coś ta hierarchia chyba jest, nie?

Strata:

  • duży narzut pamięciowy
  • duży narzut obliczeniowy (uogólnione metody, głównie liczące z wektorów i funkcji trygonometrycznych)
  • wymaga znajomości w/w metod wektorowych i trygonometrycznych :)
0

witam chyba masz racje ale nie wiem jak sobie z tym poradzić
oto lin do programu
proszę o pomoc
pozdrawiam

http://www.ac.top100.net.pl/cpp2/WinApp.rar

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