Forum: C++: Hjälp med en övning, någon?

Forum huvudsida -> Programmering -> C++: Hjälp med en övning, någon?

Sidor: 1 2

Till botten

Nissebosselasse 17:49 - 25:e Juli 2006 | Post #26
Medlem
Inlägg: 490


Skicka PM
Tja, this är ju (vad jag vet) det enda sättet för klassen att få tag på instansen av "sig själv", så att säga. Användningsområdena är väl oändliga (beroende på problemlösningen), och du såg ju hur lätt det gick att lösa kloningsproblemet ovan med hjälp av this-pekaren. Fundera lite på hur du skulle löst det utan this...

I din förra post skrev du:
  1.  
  2. // samma betydelse
  3. TheShapeList[i]->move(dx,dy);
  4. (*this).TheShapeList[i]->move(dx,dy);
  5. this->.TheShapeList[i]->move(dx,dy);

Jag antar att du var för snabb på tangenterna på den sista (this->.The...), eftersom det inte ska vara någon punkt efter ->.

Nu ska jag äta Corn Flakes!

-------------------------
http://pushingcows.se
Gula Nallen



olle 17:57 - 25:e Juli 2006 | Post #27
Medlem
Inlägg: 57


Skicka PM
stämmer mycket väl att jag råkade ta med punkt för mycket Smiley

Verkar som jag börjar förstå lite grann vad this är och hur den fungerar. Innan var jag lite borta Smiley

När man ska göra Destruktorn. Måste jag göra för alla klasser?

Sen undrar jag varför Shapes Destruktorn måste vara virtual. För i övningen säger den utan virtual så anropas inte ~Group() för gruppobjekt som pekas ut av Shape pekaren?

Blir nästan lite sugen på corn flakes nu när du nämner det Smiley



-------------------------
Ingen signatur!



Nissebosselasse 18:27 - 25:e Juli 2006 | Post #28
Medlem
Inlägg: 490


Skicka PM
Här är en bra förklaring på frågan: http://www.codersource.net/cpp_virtual_destructors.html

Lite off-topic: jag reagerar varje gång jag skriver/läser orden konstruktor / destruktor. De är ju uppenbarligen direkt tagna från engelskans "constructor" / "destructor".
Borde man inte istället på svenska säga "konstruktör" och...tja..."förgörare"? Smiley

EDIT: Det smakade väldigt bra med Corn Flakes, men nu väntar något ännu bättre: kaffe!

-------------------------
http://pushingcows.se
Gula Nallen

Senast redigerad 18:28 - 25:e Juli 2006


olle 19:11 - 25:e Juli 2006 | Post #29
Medlem
Inlägg: 57


Skicka PM
Var en bra föklaring till det som jag ej förstog, tack för länken.

Håller med dig att översättningen från engelska till svenska är lite fel. Brukar även ibland vara fel när dom översätter en film title som ska visas på tv.
Ibland vet man inte ens vilken film det är förran man har sett lite i början. Smiley


Har nu försökt göra Destruktorn ( förgörare ) för Group.


  1. Group::~Group() {
  2. for(int i=0;i<TheShapeList.size();i++)
  3. delete [] TheShapeList[i];
  4. delete [] TheShapeList;
  5. }


Ser väl bra ut? Smiley

Kan säga att jag nästan aldrig definerar destruktor. Lite dålig med det.

Sen när jag tänkte göra ~Shapes() så blev det lite stopp där. Samma sak med Circle och resterande. Vad är de jag ska "delete"?


Jag föredrar te framför kaffe. Har väl blivit en vana Smiley


-------------------------
Ingen signatur!

Senast redigerad 19:22 - 25:e Juli 2006


olle 19:38 - 25:e Juli 2006 | Post #30
Medlem
Inlägg: 57


Skicka PM
såg att det var lite kompileringsfel. Men andå efter det fick jag Segmentfault eller va de heter. och SEGABRT Smiley

  1.  
  2. Group::~Group() {
  3.  
  4. for(int i=0;i<TheShapeList.size();i++)
  5. delete TheShapeList[i];
  6. }


Synd att man inte kan slippa Destruktorn heh

-------------------------
Ingen signatur!



Nissebosselasse 20:27 - 25:e Juli 2006 | Post #31
Medlem
Inlägg: 490


Skicka PM
När du klonar ett Group-objekt, så kopieras listan med Shape-pekare (TheShapeList) från det ena objektet till det andra.
Så fastän du har enskilda Group-objekt, så innerhåller deras lista (TheShapeList, som sagt) samma lista med pekaradresser.
Du har lagt in i "förgöraren" (destruktorn Smiley ) för Group-klassen, att varje pekaradress i listan ska tas bort med delete, när Group-objektet själv förstörs (vid programmets slut, exempelvis), vilket är helt rätt. Men detta sker ju för varje instans av Group-objektet, och eftersom alla Group-kloner har samma lista med pekaradresser, kommer nästa Group-objekt/klon att ha en lista med felaktiga pekaradresser (eftersom de har blivit borttagna av en annan Group-klon).

Om de nästföljande klonerna bara vill ta bort/rensa sin lista (med delete), så är det inga problem; att köra delete på en tidigare borttagen pekare, orsakar inga fel. Men om någon klon vill använda objekten i sin lista (via t.ex. TheShapeList[i]->move (10, 10)), så kommer ju den pekaradressen att vara ogiltig.

Hoppas det inte blev för rörigt...

-------------------------
http://pushingcows.se
Gula Nallen



olle 20:50 - 25:e Juli 2006 | Post #32
Medlem
Inlägg: 57


Skicka PM
Blev lite rörigt, men förstår vad du menar. Men hur ska man unvika detta? För det finns bara TheShapeList som man har access till när man ska definera Destruktorn?


Har ju sett att man i samma funktion som man allokerar så deallokera man oxo. Man gör en test innan etc..
Ska man delete i clone kanske? Eller så är jag helt borta.

-------------------------
Ingen signatur!

Senast redigerad 20:50 - 25:e Juli 2006


Nissebosselasse 21:00 - 25:e Juli 2006 | Post #33
Medlem
Inlägg: 490


Skicka PM
Man kan ju, istället för att kopiera de rena pekaradresserna (som du gör nu, med push_back), skapa nya instanser av Shape-objekten i listan för varje ny instans av Group-klonen (jag antar att det är så övningen är tänkt att lösas).

Detta förutsätter att kopieringskonstruktören ( Smiley ) för Shape-klassen fungerar...

Detta är ett bara ett snabbt svar, återkommer med mer när jag testat själv (sitter och skriver på andra saker nu...)!

-------------------------
http://pushingcows.se
Gula Nallen



olle 21:17 - 25:e Juli 2006 | Post #34
Medlem
Inlägg: 57


Skicka PM
Har ingen kopieringskonstruktor i shape vad jag vet.

  1.  
  2. class Shape {
  3. public:
  4. Shape(QWidget *aWidget,const char *n,QColor c,Point p);
  5. void getName(char *str) const;
  6. virtual ~Shape();
  7. QColor getColor() const;
  8. void setColor(QColor c);
  9. Point getPos() const;
  10. void moveTo(Point p);
  11. virtual void move(int dx,int dy);
  12. // pure virtual functions
  13. virtual void draw() const = 0; // only implemented
  14. virtual void erase() const = 0; // in subclasses
  15. virtual Shape* clone() const = 0;
  16. protected:
  17. char myName[100];
  18. QColor myColor;
  19. Point myPos;
  20. QWidget *theWidget;
  21. };
  22.  


Tanken i uppgiften är att en grupp kan tex innehålla en ellipse, två rektanglar eller varför inte en annan delgroup med cirklar och kvadrat. Sen när man gör klone så ska väl allt som finns i just group objektet klonas. dvs allt i vectorn av typen Shape*.

Här finns frågan ifall jag föklarat dåligt Smiley


http://img228.imageshack.us/img228/6748/groups1oz8.jpg
http://img157.imageshack.us/img157/6586/groups2qj0.jpg

Har ingen brådska, så de e lungt.


-------------------------
Ingen signatur!



Nissebosselasse 21:45 - 25:e Juli 2006 | Post #35
Medlem
Inlägg: 490


Skicka PM
Okej, så här löste jag det: istället för att trycka dit pekaradresserna, så anropar jag clone hos varje Shape-instans i listan, och lägger till returvärdet från den funktionen (Shape *Clone () const).
Kloningsfunktionen hos Shape-klassen blev precis som den hos Group-klassen:
  1. Shape *Shape::Clone () const
  2. {
  3. Shape *shape = new Shape(m_number);
  4. return shape;
  5. }

Konstruktören får en parameter (som förväntas), så att den kan skapa en instans som visserligen är unik (den skapas ju med new), men som ändå får samma värde eftersom det kopieras (m_number).

Alltså, konstruktören hos din Shape-klass tar ju också ett antal parametrar (Shape (QWidget *aWidget,const char *n,QColor c,Point p);), som i sin tur sätter dessa värden för klassen. Det är samma princip som mitt exempel ovan.

Jag märker att mina förklaringar blir mer och mer röriga, så jag ska försöka ladda upp hela min källkod i en zip-fil nu (det ska väl gå här om jag inte minns fel...). Det är oftast lättare att själv stega igenom hela källkoden än att lyssna på någon som försöker förklara den... Smiley
Observera som jag sagt innan: det går naturligtvis inte att bara klippa och klistra in min källkod i ditt projekt. Men du ser ju i alla fall tekniken jag använt.

EDIT: så där, laddade upp det som "shape.zip" under min användarprofil (tror jag det ska finnas...).

EDIT2: hmm, verkar inte finnas där, men den är ändå uppladdad...? Jaja, den finns här också: http://pushingcows.se/shape.zip

-------------------------
http://pushingcows.se
Gula Nallen

Senast redigerad 21:54 - 25:e Juli 2006


olle 01:07 - 26:e Juli 2006 | Post #36
Medlem
Inlägg: 57


Skicka PM
Har nu gjort ändringarna så att i group copykonstruktorn så anropar den clone för just den objekt typ som berör så att säga.

  1. Group::Group( const Group & x) : Shape(x) {
  2. Group &x2 = const_cast<Group&>(x);
  3. vector<Shape *>::iterator it = x2.beginIterator();
  4. TheShapeList.clear();
  5. for (; it != x2.endIterator(); ++it)
  6. TheShapeList.push_back ((*it)->clone()); // innan utan clone()


Sen har jag redan alla mina clone funktioner i ellipse, rektangle, cirkel etc redan såsom din princip.


  1. Rectangle* Rectangle::clone()const {
  2. Rectangle *rp = new Rectangle(theWidget,myName,myColor,myPos,myWidth,myHeight);
  3. return rp;


Och dom resterande clone funktioner är desamma fast skillnaden

Circle(theWidget,myName,myColor,myPos,myRadius);
Ellipse(theWidget,myName,myColor,myPos,myXradius,myYradius);
etc..

I shape::clone() skulle man ej använda utan den är rent virtuel pga att det finns inget där som ska ritas (draw).

Sist men inte minns i Group::clone() är det som vanligt som du visat.

  1. Group* Group::clone()const {
  2. Group *gp = new Group(*this);
  3. return gp;
  4. }


Och det verkar som det fungerar, får ingen segment fault eller SIGABRT. Smiley Kanske var onödigt och visa vad jag gjorde när det andå fungerar. Tänkte kanske någon annan ville veta det.

Så nu behöver jag ej definera "virtual ~Shape(){}
och för Circle, Ellipse etc?

För allt sköts nu via Groups destruktorn, stämmer det?

Tack för att du orkar stå ut med mig med alla mina dumma frågor Smiley

Kanske dags och sova nu, börjar bli sent.

Ps: Du föklarar väldigt bra. Behövde inte gå igenom din kod för och förstå vad du menar.

Edit:

Glömde visa hur Destruktorn för Group ser ut ifall någon undrar.

  1.  
  2. Group::~Group() {
  3. for(int i=0;i<TheShapeList.size();i++)
  4. delete TheShapeList[i];
  5. }


-------------------------
Ingen signatur!

Senast redigerad 01:09 - 26:e Juli 2006


Nissebosselasse 10:06 - 26:e Juli 2006 | Post #37
Medlem
Inlägg: 490


Skicka PM
Eftersom alla klasser ärver från Shape, så ska basklassens "förgörare" (destruktor) vara virtuell; dom andra ärvda klassernas förgörare behöver inte vara virtuella (såvida du inte tänkt ärva från dom i sin tur).

Det är bara för att garantera att basklassens förgörare anropas vid delete.

Och egentligen, det är ju inte svårare än att skriva virtual ~Shape () {}...och då kan man ju lika gärna göra det Smiley

Vad bra att det löste sig! Nu ska jag äta frukost...

-------------------------
http://pushingcows.se
Gula Nallen



olle 13:41 - 26:e Juli 2006 | Post #38
Medlem
Inlägg: 57


Skicka PM
Tack för informationen Smiley

Tänkte bara påpeka att virtualiteten ärvs även om om en tredje klass ärver.


  1.  
  2. class Base{
  3. public:
  4. virtual void f(){ cout << "base";}
  5. ....
  6. }
  7.  
  8. class Sub : public Base{
  9. public:
  10. void f(){ cout << "sub";} // slipper skriva virtual om jag vill ha dynamiskt binding pga den ärvs från Base ända ner till SubSub
  11. ....
  12. }
  13.  
  14.  
  15. class SubSub : public Sub{
  16. public:
  17. void f(){ cout << "subsub";}
  18. ....
  19. }


Kan säga att utan dig hade jag ej löst denna övning. Tack för all hjälp och ork Smiley

Ha de gött tills kanske kommer med nåt annat nytt


-------------------------
Ingen signatur!



Sidor: 1 2

Forum huvudsida -> Programmering -> C++: Hjälp med en övning, någon?
Atom feed

Du får inte posta i den här tråden | Till toppen