/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
Spørgsmål til rigtig brug af polymorfi ill~
Fra : Flare


Dato : 23-09-02 13:01

Hejsa

Jeg har et spørgsmål ang. hvordan man laver et "rigtig" polymofisk kald
(C++):

Jeg har følgende struktur:>
http://anders.pings.dk/images/projekt/classdia.gif

Button_Controler skal lave et polymorfisk kald på Button klassens
is_Pressed() funktion.
Hvordan gør men dette korrekt? Hvad jeg umiddelbart havde tænkt mig npget
ligende:
-----------------------------
Class Button
{ bool virtual is_Pressed() = 0;

Class Button_Activate : public Button
{ bool is_Pressed(); }

Class Button_Controler
{ check_Buttons(); }

Button_Controler::Check_Buttons()
{
Button *ButObj;
Button_Activate ButActiObj;
ButObj = ButActiObj;
ButObj->Is.Pressed()
}
----------------------
Grunden til m it spørgsmål er at dette jo kræver en forbindelse fra
Button_Controler til alle Button_XXX klasserne.
Men de er jo ikke illustreret`??? Ligger de implicit i diagrammet eller er
det en mere "elegant" måde at lave det polymorfikse kald.

Håber nogen kan hjælpe mig
Anders (Nybynder i nedarvning og polymorfi)








Og stemmer UML diagrammet overens med det jeg øns



 
 
Mogens Hansen (23-09-2002)
Kommentar
Fra : Mogens Hansen


Dato : 23-09-02 17:32

"Flare" <dct_flare@hotmail.com> wrote

[8<8<8<]
> http://anders.pings.dk/images/projekt/classdia.gif
>

Kan du forklare lidt om hvordan Button_Activate, Button_Calibrate etc.
adskiller sig fra hinanden ?

Er der nogen grund til at der er en hård 4 kardinalitet ?

[8<8<8<]
> Button_Controler::Check_Buttons()
> {
> Button *ButObj;
> Button_Activate ButActiObj;
> ButObj = ButActiObj;
> ButObj->Is.Pressed()

Hvorfor vil du have IsPressed til at være run-time polymorphisk ?
Du kender jo eksakt typen (Button_Activate) på dette sted.

Hvad sker der når IsPressed kaldes ?

[8<8<8<]
> Grunden til m it spørgsmål er at dette jo kræver en forbindelse fra
> Button_Controler til alle Button_XXX klasserne. Men de er jo ikke
> illustreret`??? Ligger de implicit i diagrammet eller er det en mere
> "elegant" måde at lave det polymorfikse kald.

Det er en sundt at du undrer dig over at Button_Controller skal kende alle
specialiseringerne af Button.

Som jeg læser diagrammet er Button_Controller og Button det abstrakte
interface som en applikation ser, og Button_Calibrate etc. er de konkrete
implementeringer af Button.

Designet har en cirkulær afhængighed, idet det konkrete afhænger af det
abstrakte (ved at arve) og det abstrakte afhænger af det konkrete (ved at
nævne det ved navn i implementeringen).
Der er et godt princip (The Dependency Inversion Principle), der bl.a. siger
at abstraktioner skal ikke afhænge af detaljer, men detaljer skal afhænge af
abstraktionen.
Se Robert C. Martins gode OO-design principper
http://www.objectmentor.com/resources/articles/dip.pdf
som er en del af
http://www.objectmentor.com/resources/articles/Principles_and_Patterns.PDF
Alle 10 principper findes mere detaljeret beskrevet på
http://www.objectmentor.com. Det er et glimrende sted, med mange gode
artikler om design, patterns og udviklingsprocess.

En almindelig variant af problemet i OO-systemer er kendt som "Fragile Base
Class", hvor base-klassen afhænger af specialiseringerne. Det er generelt
usundt, og et tegn på at koden er ved at forfalde.

Ud fra "The Dependency Inversin Principle" er problemet, sådan som du også
selv antyder, at Button_Controller afhænger af Button_Calibrate etc.

Du kan fjerne den afhængighed ved at lade Button constructoren registrere
hvert _instans_ i en container (f.eks. std::vector) og lade Button
destructoren afregistrere instansen fra containeren.
Button_Controller::Check_Buttons vil så kunne gøre sit arbejde ved at
iterere igennem containeren og kalde Is_Pressed polymorfisk på alle
instancerne.
Destructoren tl Button_Controller kan så nedlægge alle Button objekterne i
containeren.

Vær sikker på at du forstår forskellen og sammenhængen mellem klasser og
objekter.

Eventuelt skulle overveje om du virkelig har brug for 4 specialisering,
eller om du blot har brug for 4 instanser af samme klasse.
Hvis den eneste forskel mellem knapperne er hvad der konkret sker, når der
trykkes på dem kan du give hvert instans information om hvad de skal udføre
med i constructoren.
I det scenarie vil PushButton være en specialisering af Button.
Der er ofte tvivl om hvornår man skal lave specialiseringer og hvornår man
skal parameterisere variation. God smag og erfaring er væsentlige elementer
i at vælge i sådanne tvivlstilfælde.
Det hører ikke specielt sammen med OO-design.
Kig på C funktionen "realloc", som tager så mange parametre at den udgør et
komplet interface til en heap-manager - "malloc" og "free" er overflødige.
At de alligevel findes er et udtryk for god smag og erfaring (i forhold til
_kun_ at have "realloc")


Venlig hilsen

Mogens Hansen




"Flare" <dct_flare@hotmail.com> wrote in message
news:<3d8f0294$0$62709$edfadb0f@dspool01.news.tele.dk>...

[8<8<8<]
> http://anders.pings.dk/images/projekt/classdia.gif
>

Kan du forklare lidt om hvordan Button_Activate, Button_Calibrate etc.
adskiller sig fra hinanden ?

Er der nogen grund til at der er en hård 4 kardinalitet ?

[8<8<8<]
> Button_Controler::Check_Buttons()
> {
> Button *ButObj;
> Button_Activate ButActiObj;
> ButObj = ButActiObj;
> ButObj->Is.Pressed()

Hvorfor vil du have IsPressed til at være run-time polymorphisk ?
Du kender jo eksakt typen (Button_Activate) på dette sted.

Hvad sker der når IsPressed kaldes ?

[8<8<8<]
> Grunden til m it spørgsmål er at dette jo kræver en forbindelse fra
> Button_Controler til alle Button_XXX klasserne. Men de er jo ikke
> illustreret`??? Ligger de implicit i diagrammet eller er det en mere
> "elegant" måde at lave det polymorfikse kald.

Det er en sundt træk at du undrer dig over at Button_Controller skal kende
alle specialiseringerne af Button.

Som jeg læser diagrammet er Button_Controller og Button det abstrakte
interface som en applikation ser, og Button_Calibrate etc. er de konkrete
implementeringer af Button.

Designet har en cirkulær afhængighed, idet det konkrete afhænger af det
abstrakte (ved at arve) og det abstrakte afhænger af det konkrete (ved at
nævne det ved navn i implementeringen).
Der er et godt princip (The Dependency Inversion Principle), der bl.a. siger
at abstraktioner skal ikke afhænge af detaljer, men detaljer skal afhænge af
abstraktionen.
Se Robert C. Martins gode OO-design principper
http://www.objectmentor.com/resources/articles/dip.pdf
som er en del af
http://www.objectmentor.com/resources/articles/Principles_and_Patterns.PDF
Alle 10 principper findes mere detaljeret beskrevet på
http://www.objectmentor.com. Det er et glimrende sted, med mange gode
artikler om design, patterns og udviklingsprocess.

En almindelig variant af problemet i OO-systemer er kendt som "Fragile Base
Class", hvor base-klassen afhænger af specialiseringerne. Det er generelt
usundt, og et tegn på at koden er ved at forfalde.

Ud fra "The Dependency Inversin Principle" er problemet, sådan som du også
selv antyder, at Button_Controller afhænger af Button_Calibrate etc.

Du kan fjerne den afhængighed ved at lade Button constructoren registrere
hvert _instans_ i en container (f.eks. std::vector<Button*>) og lade Button
destructoren afregistrere instansen fra containeren.
Button_Controller::Check_Buttons vil så kunne gøre sit arbejde ved at
iterere igennem containeren og kalde Is_Pressed polymorfisk på alle
instancerne.
Destructoren tl Button_Controller kan så nedlægge alle Button objekterne i
containeren.

Vær sikker på at du forstår forskellen og sammenhængen mellem klasser og
objekter.

Jeg tror desuden at du skulle overveje om du virkelig har brug for 4
specialisering, eller om du blot har brug for 4 instanser af samme klasse.
Hvis den eneste forskel mellem knapperne er hvad der konkret sker, når der
trykkes på dem kan du give hvert instans information om hvad de skal udføre
med i constructoren.
I det scenarie vil PushButton være en specialisering af Button.

Der er ofte tvivl om hvornår man skal lave specialiseringer og hvornår og
hvordan man skal parameterisere variation. God smag og erfaring er
væsentlige elementer i at vælge i sådanne tvivlstilfælde.
Det hører ikke specielt sammen med OO-design.
Kig på C funktionen "realloc", som tager så mange parametre at den udgør et
komplet interface til en heap-manager - "malloc" og "free" er overflødige.
At de alligevel findes er så afgjort et udtryk for god smag og erfaring (i
forhold til _kun_ at have "realloc")


Venlig hilsen

Mogens Hansen



Flare (25-09-2002)
Kommentar
Fra : Flare


Dato : 25-09-02 16:44

> Som jeg læser diagrammet er Button_Controller og Button det abstrakte
> interface som en applikation ser, og Button_Calibrate etc. er de konkrete
> implementeringer af Button.

Rigtig set. Efter at have læst dit indlæg og snakket med nogle andre om
problemstillinge er vi kommet frem til følgende struktur istedet:
http://anders.pings.dk/images/projekt/test.gif

Her er det de afledte Buttons der "styre" slagets gang. De vil nok i sidste
ende komme til at kører i threads men lad det nu ligge. Vil du eller en af
jer andre mene af dette design vil muligøre Polymorfiske kald fra fx.
Button_Activate til CruiseControl og udfører den specifike kald på
Crusiecontrol. Activate_CC(). Jeg ved godt at polymorfine måske er lidt
søgt, men da det er en del af et projekt vil vi meget gerne vise at vi kan.

Kernen af spørgsmålet er: Kan fx Button_Activate lave et polymorfisk kald
til en specifik operation i CruiseControl klassen?

Mvh
Anders








Mogens Hansen (25-09-2002)
Kommentar
Fra : Mogens Hansen


Dato : 25-09-02 19:17


"Flare" <dct_flare@hotmail.com> wrote in message
news:3d91d9cd$0$84701$edfadb0f@dspool01.news.tele.dk...
> > Som jeg læser diagrammet er Button_Controller og Button det abstrakte
> > interface som en applikation ser, og Button_Calibrate etc. er de
konkrete
> > implementeringer af Button.
>
> Rigtig set. Efter at have læst dit indlæg og snakket med nogle andre om
> problemstillinge er vi kommet frem til følgende struktur istedet:
> http://anders.pings.dk/images/projekt/test.gif

Ikke for at gøre dig ked af det, men prøv selv at sammenligne
http://anders.pings.dk/images/projekt/classdia.gif
http://anders.pings.dk/images/projekt/test.gif
og se efter forskelle.
Jeg kan se at en klasse er blevet omdøbt, og yderligere specificeret, og en
member funktion er blevet omdøbt.

Jeg kan ikke se nogen strukturelle forskelle.
Jeg kan ikke se at der er lavet om i kobling og cirkulær afhængigheder -
ligesom jeg heller ikke af det oprindelige UML diagram kunne se at der var
cirkulære afhængigheder. Det kunne jeg se af den skitserede kode.

Problemet er ikke tegningerne i sig selv.
Man skal blot være klar over at tegningerne ikke indeholder al information -
hvis de gjorde var der ikke nogen grund til at skrive programmet, det ville
entydigt kunne genereres af enhver.
Det er min erfaring at UML diagrammer er glimrende til at formidle et
overblik, og til at illustrere en mere detaljeret forklaring. De er ofte
glimrende som grundlag for diskution mellem folk, der på forhånd kender
designet.

[8<8<8<]
> Kernen af spørgsmålet er: Kan fx Button_Activate lave et polymorfisk kald
> til en specifik operation i CruiseControl klassen?

Ja.
Men hvor kom det (run-time) polymorfiske ind i billedet ?
Hvorfor er det væsentligt på dette niveau ?
Det er formodentlig begrundet i noget med kobling, genbrug eller abstraktion
går jeg ud fra, idet selve konfigurationen forekommer mig at være run-time
statisk (een Button_Calibrate, een Button_Resume, een Button_Deactivate, een
Button_Activate og een Cruise_Controller).
(Hvis du bliver mere forvirret, og ikke ved hvad du skal svare, så bare lad
spørgsmålet ligge og kør videre. Husk spørgsmålene - du kommer i nærheden af
dem senere).

Venlig hilsen

Mogens Hansen



Flare (25-09-2002)
Kommentar
Fra : Flare


Dato : 25-09-02 20:09

> Jeg kan ikke se nogen strukturelle forskelle.

Nej ikke somsåden vel. Men forskellen er at kommunikationes vejen er blevet
ændret. Ikke så tydeligt ken jeg nu se. Men ideen er at knapper er dem der
har ansvaret for at starte det polymorfiske kald...igen ..hvis det kan lade
sig gøre. Man kunen tænke sig at når en knap bliver aktiveret at et
interrupt vil den kalde Button_Pressed.

Du vil gerne se noget kilde kode. Dette vil jeg ikke begive mig ind på.
(havde måske den utopiske forestilling) at nogen forstod problemstillingen
og kunen komme med et kode eks.

Men måske ER problemet bare forkert stillet op?

Anders



Mogens Hansen (25-09-2002)
Kommentar
Fra : Mogens Hansen


Dato : 25-09-02 20:53


"Flare" <dct_flare@hotmail.com> wrote in message
news:3d9209df$0$84669$edfadb0f@dspool01.news.tele.dk...

[8<8<8<]
> Man kunen tænke sig at når en knap bliver aktiveret at et
> interrupt vil den kalde Button_Pressed.

Er det et embedded system ?
Er det en skole opgave ?
Hvad er det for discipliner der forventes anvendt ?
F.eks. OO design og UML diagrammer, C++ programmering, interrupt-håndtering,
multi-trådet programmering ?

> Du vil gerne se noget kilde kode. Dette vil jeg ikke begive mig ind på.
> (havde måske den utopiske forestilling) at nogen forstod problemstillingen
> og kunen komme med et kode eks.

Det ender jo nok med at opgaven er din egen.
Nogle hint og ledende spørgsmål kan du sikkert godt få.
Hvis du selv skriver noget kode, og har et konkret problem, kan du sikkert
også godt få noget hjælp.

> Men måske ER problemet bare forkert stillet op?

Nej, jeg det har jeg ikke set noget tegn på.
Jeg opfatter nærmere at problemet ikke er blevet formuleret endnu.
Er det der sår tvivl hos dig, f.eks.
* hvordan skal systemet designes, og hvilke OO elementer bruges ?
* hvad polymorfiske funktioner er i C++, hvad de gør og hvordan man bruger
det ?

Det er sikkert udemærket hvad du allerede har lavet. Fortvivl ikke over at
det givetvis kan forbedres.

Venlig hilsen

Mogens Hansen







Flare (25-09-2002)
Kommentar
Fra : Flare


Dato : 25-09-02 20:58

> Er det et embedded system ?
Ja
> Er det en skole opgave ?
Ja
> Hvad er det for discipliner der forventes anvendt ?
OOP, UML, Krav til polymorfi

> F.eks. OO design og UML diagrammer, C++ programmering,
interrupt-håndtering,
> multi-trådet programmering ?
Ja alt det der

> Nej, jeg det har jeg ikke set noget tegn på.
Godt

> Er det der sår tvivl hos dig, f.eks.
> * hvordan skal systemet designes, og hvilke OO elementer bruges ?

Nej ikke så meget

> * hvad polymorf iske funktioner er i C++, hvad de gør og hvordan man
bruger
> det ?

JA! Jeg har ingen problemed "normal consol" programering og brug af klasser
og simpel nedarvning. Jeg har bare meget svæert ved at gennemskue hvordan
polymorfi konkret virker. Jeg kan godt se det smarte og noget af vejen
forstå mekanismen bag. Jeg kan dog ikke koble hvordan man fx kalder en række
sensorer polymorfisk igennem en basepointer og derudfra gå en række værdier
tilbage som man med sikkerhed kan spore tilbage til den "reele" sensor. Nu
kom jeg god tnok ind på et andet problem. Men der er ikke forskel som sådan
i det jeg øsnerk opnået. Jeg vil heller ikke have en løsning. Men måske
nogen kunne vise eller refere til en makanisme der viser nogle klasse
definationer eller bare noget lidt _konkret_


> Det er sikkert udemærket hvad du allerede har lavet. Fortvivl ikke over at
> det givetvis kan forbedres.

Indtil vidre tal for hjælpen
ANders



Mogens Hansen (29-09-2002)
Kommentar
Fra : Mogens Hansen


Dato : 29-09-02 18:00


"Flare" <dct_flare@hotmail.com> wrote in message
news:3d936159$0$69067$edfadb0f@dspool01.news.tele.dk...


[8<8<8<]
> Jeg har bare meget svæert ved at gennemskue hvordan
> polymorfi konkret virker.

Run-time polymorfi i C++ er typisk implementeret med virtuelle member
funktioner.
Det virker typisk på den måde at en klasse med virtuelle metoder har et
skjult data-medlem (som man ikke har adgang til). Dette data-medlem kaldes
typisk "vptr" og er en pointer der peger på en funktions-tabel, der er
specifik for den konkrete klasse og delt mellem alle instanser. Tabellen
kaldes typisk "vtbl" eller Virtual Table.
Når der skal kaldes en virtuel metode, genererer compileren kode til at
følge "vptr" og slå op i den virtuelle funktions tabel og kalde den funktion
der står der.

Konkret.
Vi har en abstrakt basis-klasse (ikke compileret - der kan være småfejl)

class figure
{
public:
unsigned area() const = 0;
unsigned perimeter() const = 0;

protected:
virtual ~figure();
};

class circle : public figure
{
public:
circle(unsigned center_x, unsigned center_y, unsigned radius);
unsigned area() const;
unsigned perimeter() const;

private:
unsigned center_x_;
unsigned center_y_;
unsigned radius_;
};

class rectangle : public figure
{
public:
rectangle(unsigned left, unsigned top, unsigned right, unsigned bottom);
unsigned area() const;
unsigned perimeter() const;

private:
unsigned left_;
unsigned top_;
unsigned right_;
unsigned bottom_;
};

Her vil compileren typisk lægge klasserne ud som:

figure layout:
------------- -------------
| vptr | ---> | destructor | -> &figure:figure
------------- -------------
| area | -> &pure_virtual
------------
| perimeter | -> &pure_virtual
-------------



circle layout:
------------- -------------
| vptr | ---> | destructor | -> &circle:circle
------------- -------------
| center_x_ | | area | -> &circle::area
------------- ------------
| center_y_ | | perimeter | -> &circle::perimeter
------------- -------------
| radius_ |
-------------

rectangle laytout:
------------- -------------
| vptr | ---> | destructor | -> &rectangle:rectangle
------------- -------------
| left_ | | area | -> &rectangle::area
------------- ------------
| top_ | | perimeter | -> &rectangle::perimeter
------------- -------------
| right_ |
-------------
| bottom_ |
-------------

Når så man har en funktion

unsigned area(const figure* f)
{
return f->area();
}

laver compileren typisk det om til
unsigned area(const figure* f)
{
return (*f->vptr[1])();
}

På den måde bliver det på run-time bestemt hvilken funktion der faktisk
kaldes afhængigt af den konkrete type af "f".
Man kan forhåbentlig også se at run-time polymorfi kræver at man arbejder
med pointere (eller referencer) til en base-klasse.

Venlig hilsen

Mogens Hansen



Mogens Hansen (25-09-2002)
Kommentar
Fra : Mogens Hansen


Dato : 25-09-02 20:58


"Flare" <dct_flare@hotmail.com> wrote in message
news:3d9209df$0$84669$edfadb0f@dspool01.news.tele.dk...

[8<8<8<]
> Man kunen tænke sig at når en knap bliver aktiveret at et
> interrupt vil den kalde Button_Pressed.

Er det et embedded system ?
Er det en skole opgave ?
Hvad er det for discipliner der forventes anvendt ?
F.eks. OO design og UML diagrammer, C++ programmering, interrupt-håndtering,
multi-trådet programmering ?

> Du vil gerne se noget kilde kode. Dette vil jeg ikke begive mig ind på.
> (havde måske den utopiske forestilling) at nogen forstod problemstillingen
> og kunen komme med et kode eks.

Det ender jo nok med at opgaven er din egen.
Nogle hint og ledende spørgsmål kan du sikkert godt få.
Hvis du selv skriver noget kode, og har et konkret problem, kan du sikkert
også godt få noget hjælp.

> Men måske ER problemet bare forkert stillet op?

Nej, jeg det har jeg ikke set noget tegn på.
Jeg opfatter nærmere at problemet ikke er blevet formuleret endnu.
Er dit det der sår tvivl hos dig, f.eks.
* hvordan skal systemet designes, og hvilke OO elementer bruges ?
* hvad polymorfiske funktioner er i C++, hvad de gør og hvordan man bruger
det ?

Det er sikkert udemærket hvad du allerede har lavet. Fortvivl ikke over at
det givetvis kan forbedres.

Venlig hilsen

Mogens Hansen







Søg
Reklame
Statistik
Spørgsmål : 177485
Tips : 31964
Nyheder : 719565
Indlæg : 6408407
Brugere : 218885

Månedens bedste
Årets bedste
Sidste års bedste