/ 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
Typedef i en h-fil
Fra : Bertel Lund Hansen


Dato : 27-02-02 10:18

Hej alle

Jeg har en typeerklæring:

   typedef struct {
      void *p;
      int size;
   } myarray;

Den skal stå i et modul, men nu er jeg i tvivl om hvordan den
skal erklæres i headerfilen.


 
 
Igor V. Rafienko (27-02-2002)
Kommentar
Fra : Igor V. Rafienko


Dato : 27-02-02 15:15

[ Bertel Lund Hansen ]

[ snip ]

>    typedef struct {
>       void *p;
>       int size;
>    } myarray;
>
> Den skal stå i et modul, men nu er jeg i tvivl om hvordan den skal
> erklæres i headerfilen.


$ cat a.h
#ifndef MYARRAY_H
#define MYARRAY_H

typedef struct myarray {
void *p;
size_t size;
} myarray;


myarray*
make_myarray( /* ?? */ );

void
free_myarray( /* ?? */ );

/* etc. */

#endif
$


Fx. slik? include-guards for å kunne #include'e filen gjentatte
ganger. En "merkelig" typedef for å kunne si både "struct myarray" og
"myarray". Det er også lurt[tm] å føye til deklarasjoner av de
funksjonene som jobber med myarrays (jeg kunne ikke komme på noe annet
enn (de)allokering, men du finner sikkert flere).

Hva var det du hadde tvil om?





ivr
--
If the Americans want the gold medals this bad, then our Mint should
stamp some and hand them over.
      -- G. Raikov, 2002-02-22 on Salt Lake City Olympics

Bertel Lund Hansen (27-02-2002)
Kommentar
Fra : Bertel Lund Hansen


Dato : 27-02-02 15:56

Igor V. Rafienko skrev:

>Fx. slik? include-guards for å kunne #include'e filen gjentatte
>ganger.

Ja, dem har vi lært.

>En "merkelig" typedef for å kunne si både "struct myarray" og
>"myarray".

Jeg skal måske lige have repeteret noget om structs.

>Det er også lurt[tm] å føye til deklarasjoner av de
>funksjonene som jobber med myarrays (jeg kunne ikke komme på noe annet
>enn (de)allokering, men du finner sikkert flere).

Det er en bunden opgave vi har fået.

>Hva var det du hadde tvil om?

Det forekom mig at det var for mange detaljer at have stående i
h-filen. Jeg overvejede om der ikke der kun skulle stå en kort
deklaration og så hele erklæringen i implemmentationsfilen, lidt
ligesom en funktion.

--
Bertel
http://lundhansen.dk/bertel/   FIDUSO: http://fiduso.dk/

Igor V. Rafienko (27-02-2002)
Kommentar
Fra : Igor V. Rafienko


Dato : 27-02-02 16:16

[ Bertel Lund Hansen ]

[ snip ]

> >Hva var det du hadde tvil om?
>
> Det forekom mig at det var for mange detaljer at have stående i
> h-filen. Jeg overvejede om der ikke der kun skulle stå en kort
> deklaration og så hele erklæringen i implemmentationsfilen, lidt
> ligesom en funktion.


Mnja, det bør du sannsynligvis ikke gjøre av den grunn at dersom det
eneste som er synlig er en "forward declaration":

struct myarray;

så vil du kunne lage pekere til 'struct myarray', men ikke noe mer. Og
da er det relativt håpløst å få gjort noe som helst. IMHO.





ivr
--
If the Americans want the gold medals this bad, then our Mint should
stamp some and hand them over.
      -- G. Raikov, 2002-02-22 on Salt Lake City Olympics

Soeren Sandmann (27-02-2002)
Kommentar
Fra : Soeren Sandmann


Dato : 27-02-02 18:17

igorr@ifi.uio.no (Igor V. Rafienko) writes:

> > deklaration og så hele erklæringen i implemmentationsfilen, lidt
> > ligesom en funktion.
>
> så vil du kunne lage pekere til 'struct myarray', men ikke noe mer. Og
> da er det relativt håpløst å få gjort noe som helst. IMHO.

Det er jeg uenig i. Jeg bruger ganske ofte

i foo.h:

typedef struct Foo Foo;

Foo *foo_create (int field);
void foo_print (Foo *foo)
int foo_get_field (void);
void foo_set_field (Foo *foo, int field);

i foo.c:

struct Foo {
int field;
};

Foo *
foo_create (int field)
{
Foo *foo = malloc (sizeof (Foo));

foo->field = field;
return foo;
}

void
foo_print (Foo *foo)
{
printf ("field: %d\n", foo->field);
}

int
foo_get_field (Foo *foo)
{
return foo->field;
}

void
foo_set_field (Foo *foo, int field)
{
foo->field = field;
}

osv.

For at det skal virke bliver man nødt til at lade al tilgang til
strukturen gå gennem funktioner, men man får til gengæld fordel af
bedre indkapsling. Det at der kun bliver læst og skrevet til felter
gennem funktionerne, giver mere fleksibilitet i tilfælde hvor man
bestemmer sig for at ændre repræsentationen af informationen.

Hvis man fx finder ud af at man bruger meget tid på at holde en
bestemt variabel opdateret, kan man fjerne den helt og i stedet
generere informationen når der er brug for den. Det er i nogle
tilfælde betydeligt mere effektivt end at holde feltet opdateret hele
tiden.

Der er masser af andre eksempler på at at indkapsling er en fordel, og
essensen er altid at man med direkte adgang til felterne lover mere
end nødvendigt, nemlig at informationen i et felt kan aflæses _altid_,
hvor man ikke burde love mere end at informationen på en eller anden
måde vil være til rådighed.

Igor V. Rafienko (27-02-2002)
Kommentar
Fra : Igor V. Rafienko


Dato : 27-02-02 18:49

[ Soeren Sandmann ]

[ snip ]

> > så vil du kunne lage pekere til 'struct myarray', men ikke noe
> > mer. Og da er det relativt håpløst å få gjort noe som helst. IMHO.
>
> Det er jeg uenig i. Jeg bruger ganske ofte

[ snip kode ]

Ok, du har et meget godt poeng.

Litt mer nyansert synspunkt: det med enkapsulering er fint, _men_ det
gjelder kun dynamisk allokerte Foo'er. Dersom man trenger en slik Foo
med 'automatic storage duration', så fungerer ikke teknikken over
(altså, foo.h må inneholde definisjonen til struct Foo). Trenger du en
array av Foo'er, fungerer ikke forslaget over heller.

Det blir nok en avveiing mellom hva man trenger og hvor
"objekt-orientert" man ønsker det. Personlig disiplin er et veldig
fint redskap.

Takk for rettelsen,

[ snip ]





ivr
--
If the Americans want the gold medals this bad, then our Mint should
stamp some and hand them over.
      -- G. Raikov, 2002-02-22 on Salt Lake City Olympics

Mogens Hansen (27-02-2002)
Kommentar
Fra : Mogens Hansen


Dato : 27-02-02 21:31


"Soeren Sandmann" <sandmann@daimi.au.dk> wrote

[snip]
> int
> foo_get_field (Foo *foo)
> {
> return foo->field;
> }
>
> void
> foo_set_field (Foo *foo, int field)
> {
> foo->field = field;
> }
>
> osv.
>

Det er jo _næsten_ C++ der , dog med den forskel at klasser kan allokeres på
stakken.
Det er tæt på "handle-body" eller "pimpl" idiom i C++, hvor man også
indfører en indirektion for at skjule den faktiske implementering af
strukturen.

> For at det skal virke bliver man nødt til at lade al tilgang til
> strukturen gå gennem funktioner, men man får til gengæld fordel af
> bedre indkapsling. Det at der kun bliver læst og skrevet til felter
> gennem funktionerne, giver mere fleksibilitet i tilfælde hvor man
> bestemmer sig for at ændre repræsentationen af informationen.
>

Det var også en væsentlig grund til at klasser blev indført i C++.


Venlig hilsen

Mogens Hansen



Jesper Wolf Jesperse~ (27-02-2002)
Kommentar
Fra : Jesper Wolf Jesperse~


Dato : 27-02-02 22:37

"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:a5jfmr$2q7s$1@news.cybercity.dk...

> Det er jo _næsten_ C++ der , dog med den forskel at klasser kan
> allokeres på stakken.
> Det er tæt på "handle-body" eller "pimpl" idiom i C++, hvor man også
> indfører en indirektion for at skjule den faktiske implementering af
> strukturen.
>
> > For at det skal virke bliver man nødt til at lade al tilgang til
> > strukturen gå gennem funktioner, men man får til gengæld fordel af
> > bedre indkapsling. Det at der kun bliver læst og skrevet til felter
> > gennem funktionerne, giver mere fleksibilitet i tilfælde hvor man
> > bestemmer sig for at ændre repræsentationen af informationen.
> >
>
> Det var også en væsentlig grund til at klasser blev indført i C++.

Desværre kender jeg ikke nogen mulighed for at man i C++ kan skjule en
klasses indhold for omverdenen.
Det ville ellers være rart om man kunne nøjes med at have en interface
definition i header filen, som slet ikke nævner data elementerne, eller alle
de nødvendige copy constructorer.

Jeg vil gerne have mine header filer til at være selvforklarende så folk
ikke behøver den store C++ kundskab for at kunne bruge dem.
Men når alle de private dataelementer og selv alle servicefunktionerne skal
med, med alle deres detaljer så er det så som så med overskueligheden.

Bare kig på en hvilken som helst standard header til C++ biblioteket, de er
ulæselige og ubrugelige uden en refferencemanual.

Der er god brug for en form for opdeling af header filer i noget brugeren
kan læse og forstå, og noget compileren bruger for at få alle de væsentlige
men forvirrende detaljer med.
Men selv anvendelse af nestede includes giver, så vidt jeg kan se, ikke den
mulighed.

En interface definition som i Java ville ikke være nogen dårlig ide, men
kræver såvidt jeg kan se det en ændring i sproget.

Med venlig hilsen
Jesper Wolf Jespersen


Igor V. Rafienko (27-02-2002)
Kommentar
Fra : Igor V. Rafienko


Dato : 27-02-02 23:56

[ Jesper Wolf Jespersen ]

[ snip ]

> Desværre kender jeg ikke nogen mulighed for at man i C++ kan skjule
> en klasses indhold for omverdenen.


D'uh -- private (men det viste du vel). Ja, man vil se at attributter
finnes, men det hjelper lite, da man ikke har tilgang til dem.


> Det ville ellers være rart om man kunne nøjes med at have en
> interface definition i header filen, som slet ikke nævner data
> elementerne, eller alle de nødvendige copy constructorer.


Det er hovedsaklig et spørsmål om personlig disiplin.


> Jeg vil gerne have mine header filer til at være selvforklarende så
> folk ikke behøver den store C++ kundskab for at kunne bruge dem. Men
> når alle de private dataelementer og selv alle servicefunktionerne
> skal med, med alle deres detaljer så er det så som så med
> overskueligheden.


Mnja, egentlig ikke:

class Foo
{
public:
Foo();
Foo( const Foo &f );

Bar barOfFoo();

private:
T *little_foo;
T *bif_foo;

vector< T > lots_of_bars;
};

Hvis man ikke vil få en overskuelig oversikt, titter man på public
(evt. protected) delen av klassen. Hva little_foo/big_foo måtte bety
er isåfall irrelevant -- man vet at man kan stappe Foo i en std::
kontainer og at man kan få en Bar ut av en Foo. Holder ikke det?


> Bare kig på en hvilken som helst standard header til C++
> biblioteket, de er ulæselige og ubrugelige uden en refferencemanual.


Det er en veldig dårlig sammenligning, da standardheader er ment til å
bli lest _utelukkende_ av kompilatoren. De kan ikke bli lesbare, alene
av den grunn av det _må_ bli et hav av ifdefs og rimelig jævlige
variabelnavn for å sørge for at de ikke kolliderer med stupide makroer
som finnes ellers. Det _er_ en grunn til at gcc's <algorithm> er bare
helt horribel.

Meningen er å bruke standarden og referanser à la Dinkumware for å
vite hva man skal regne med å finne i slike headere.


> Der er god brug for en form for opdeling af header filer i noget
> brugeren kan læse og forstå, og noget compileren bruger for at få
> alle de væsentlige men forvirrende detaljer med. Men selv anvendelse
> af nestede includes giver, så vidt jeg kan se, ikke den mulighed.


Man kan vel gjøre noe slikt:

class Foo
{
public:
Foo();
Foo( const Foo &f );

Bar barOfFoo();
private:

#include "foodetails.h"
};

men, som sagt, det er mer et spørsmål om hvordan man skal lese kode.


> En interface definition som i Java ville ikke være nogen dårlig ide,
> men kræver såvidt jeg kan se det en ændring i sproget.


Man kan få Javas interface idag vha. abstrakte klasser (man kan
faktisk få mer enn det, men det blir igjen et spørsmål om disiplin).

Jeg er veldig spent på hva Bertel Lund Hansen skulle ha i oppgaven
sin.





ivr
--
If the Americans want the gold medals this bad, then our Mint should
stamp some and hand them over.
      -- G. Raikov, 2002-02-22 on Salt Lake City Olympics

Christian Hemmingsen (28-02-2002)
Kommentar
Fra : Christian Hemmingsen


Dato : 28-02-02 00:23

igorr@ifi.uio.no (Igor V. Rafienko) writes:

> [ Jesper Wolf Jespersen ]
>
> [ snip ]
>
> > Desværre kender jeg ikke nogen mulighed for at man i C++ kan skjule
> > en klasses indhold for omverdenen.
>
>
> D'uh -- private (men det viste du vel). Ja, man vil se at attributter
> finnes, men det hjelper lite, da man ikke har tilgang til dem.

_Det_ er en sandhed med modifikationer.
Betragt nedenstående...

#include <iostream>
class pub {
public:
pub(int f) : foo(f){}
int getFoo();
void setFoo(int f);
int foo;
};

int pub::getFoo(){return foo;}
void pub::setFoo(int f){foo = f;}

class prv {
public:
prv(int f) : foo(f){}
int getFoo();
void setFoo(int f);
private:
int foo;
};

int prv::getFoo(){return foo;}
void prv::setFoo(int f){ cerr << "Cannot modify foo" << endl;}

int main(int argc, char ** argv){
prv * p1 = new prv(124);
pub * p2;
int ptr;
cout << p1->getFoo() << endl;

p1->setFoo(321);

cout << p1->getFoo() << endl;

ptr = (int)p1;
p2 = (pub *)ptr;

p2->foo = 4567;

cout << p1->getFoo() << endl;

}

output:
124
Cannot modify foo
124
4567


Der er ikke en skid sikkerhed i C++'s private....


--
Christian Hemmingsen

Igor V. Rafienko (28-02-2002)
Kommentar
Fra : Igor V. Rafienko


Dato : 28-02-02 01:22

[ Christian Hemmingsen ]

[ snip ]

> > D'uh -- private (men det viste du vel). Ja, man vil se at
> > attributter finnes, men det hjelper lite, da man ikke har tilgang
> > til dem.
>
> _Det_ er en sandhed med modifikationer.


Ehh... ja, man kan også finne ut avstanden fra starten av objektet til
det aktuelle feltet og skrive de nødvendige verdiene til den aktuelle
adressen (dog, med de restriksjonene som gjelder for offsetof blir
slike øvelser ikke helt trivielle for non-POD types). Som sagt,
personlig disiplin.

Eller vil du ha en mekanisme som ikke tillot å modifisere bestemte
felt samme hva? Det blir vanskelig i alle språk -- tenk om språket
tilbyr et FFI til C (og derfra er det bare å begynne å skrible til en
passende adresse).

'private' betyr rimelig klart "ikke klå på disse datafelt". Dette kan
ikke omgås _innenfor_ språket heller (eller, vis gjerne hvordan. Jeg
tviler på at dette er mulig, men C++ er ikke min sterke side).

[ snip litt kode ]


> int main(int argc, char ** argv){
> prv * p1 = new prv(124);
> pub * p2;
> int ptr;
> cout << p1->getFoo() << endl;
>
> p1->setFoo(321);
>
> cout << p1->getFoo() << endl;
>
> ptr = (int)p1;


Vil ikke fungere. Det finnes ingen garanti for at en int er stor nok
til å inneholde peker (og ej heller at man kan få denne verdien
tilbake, selv om en int er stor nok).


> p2 = (pub *)ptr;


Nei, dette trenger ikke å fungere -- hvor finner du _garantien_ om at:

1) prv* og pub* kan konverteres seg imellom? (det eneste som språket
lover er T* -> void* -> T*. IIRC finnes det ingen garanti om at det
finnes en integral type som er stor nok til å romme en peker). Det
er ikke utenkelig at man bruker egne heaps for prv og pub, og
allocator bruker pekeradressen som intern "identifikasjon" på
hvilken heap et objekt hører til (jeg er litt inspirert av
<URL:ftp://ftp.cs.utexas.edu/pub/garbage/bigsurv.ps> idag. Man
foreslå separate heaps der av en rekke hensyn. En glimrende
oversiktsartikkel, imho).

2) Hva får deg til å tro at pub og prv har samme memory layout?
Hvordan vet du at du ikke skribler over interne klassedata
relevante for GC, debugkode e.l.? (Vennligst ikke si "det vil virke
under MVC++, og dermed er jeg lykkelig"; jeg vil ha et sitat fra
_standarden_ som _garanterer_ at dette virker under alle forhold).
Standarden åpner (temmelig eksplisitt) for at
private/public/protected kan påvirke memory layout'en.

[ snip ]


> Der er ikke en skid sikkerhed i C++'s private....


Du foreslo et verre hack enn offsetof: når man går _utenfor_ språket
er det ikke så veldig interessant å snakke om hva som kan oppnås.
Bedre eksempel?





ivr
--
If the Americans want the gold medals this bad, then our Mint should
stamp some and hand them over.
      -- G. Raikov, 2002-02-22 on Salt Lake City Olympics

Richard Flamsholt (28-02-2002)
Kommentar
Fra : Richard Flamsholt


Dato : 28-02-02 01:46

Christian Hemmingsen <postmaster@hemmingsen.nospam.kampsax.k-net.dk>
skrev:
> prv * p1 = new prv(124);
> pub * p2;
> ptr = (int)p1;
> p2 = (pub *)ptr;
>Der er ikke en skid sikkerhed i C++'s private....

Der er heller ikke en skid sikkerhed i isoleringen omkring en elledning,
for man kan jo bare skære den af. Og dog forhindrer den som udgangspunkt
folk i at få stød.

Naturligvis kan typesystemet i C++ omgås med vilje, som dit fejlagtige
program illustrerer. C++ er jo ikke et stykke hardware, der forhindrer
dig i at kunne læse de rå bytes. Som Bjarne skriver i ARM p.239:

"The C++ access control mechanisms provide protection against
accident - /not/ against fraud. Any programming language that
supports access to raw memory will leave data open [...]"

--
Richard Flamsholt
richard@flamsholt.dk - www.richard.flamsholt.dk

Mogens Hansen (28-02-2002)
Kommentar
Fra : Mogens Hansen


Dato : 28-02-02 07:36


"Christian Hemmingsen" <postmaster@hemmingsen.nospam.kampsax.k-net.dk> wrote

>
> Der er ikke en skid sikkerhed i C++'s private....
>

Du har ikke nogen som helst garanti for det du prøver at påvise virker.
At det virker på din compiler beviser _intet_.

Hvis du vil overtræde private, så gør det dog på en ordenligt, gennemført og
portabel måde (som John Lakos viser i "Large-Scale C++ Software Design):

#define private public

Iøvrigt ser jeg ikke nogen som helst grund til at C++ skulle beskytte folk,
der _bevidst_ vil opføre sig tåbeligt!

Venlig hilsen

Mogens Hansen



Mogens Hansen (28-02-2002)
Kommentar
Fra : Mogens Hansen


Dato : 28-02-02 07:36


"Jesper Wolf Jespersen" <spam.jwj@ehuset.com.spam> wrote in message
news:4kcf8.185$eq3.4109@news.get2net.dk...

>
> Desværre kender jeg ikke nogen mulighed for at man i C++ kan skjule en
> klasses indhold for omverdenen.

Det kan sagtens lade sig gøre.
Jeg har desværre ikke tid til at vise det nu, men vender tilbage med det i
aften

Venlig hilsen

Mogens Hansen



Mogens Hansen (28-02-2002)
Kommentar
Fra : Mogens Hansen


Dato : 28-02-02 17:55

Ok, så er der lige lidt tid til at svare i.


"Jesper Wolf Jespersen" <spam.jwj@ehuset.com.spam> wrote

> "Mogens Hansen" <mogens_h@dk-online.dk> wrote

>
> Desværre kender jeg ikke nogen mulighed for at man i C++ kan skjule en
> klasses indhold for omverdenen.

Det kan man sagten, og det er et ikke ualmindeligt idiom i C++.
Det går under forskellige navne:
* "handle/body" (i Advanced C++, James O. Coplien)
* "compiler firewall" eller "fully insulated concrete class" (i
Large-Scale C++ Software Design, John Lakos)
* "pimpl" (i Exceptional C++, Herb Sutter)
pimpl er en forkortelse af "Pointer to Implementation".

Hvis vi tager Søren Sandman's eksempel, og skriver det om til C++ med
anvendelse af pimpl:

// foo.h

#ifndef GUARD_FOO_H
#define GUARD_FOO_H

class foo
{
public:
foo(int field);
foo(const foo& src);
~foo();
foo& operator=(const foo& rhs);

void print(void) const;
int get_field(void) const;
void set_field(int field);

private:
class impl;
impl* impl_;
};


#endif //GUARD_FOO_H


// foo.cpp

#include "foo.h"
#include <iostream>

class foo::impl
{
public: // debatable
impl(int field) :
field_(field) {}

int field_;
};

foo::foo(int field) :
impl_(new foo::impl(field))
{
}

foo::foo(const foo& src) :
impl_(new foo::impl(*src.impl_))
{
}

foo:foo()
{
delete impl_;
}

foo& foo:erator=(const foo& rhs)
{
foo::impl* tmp_impl = new foo::impl(*rhs.impl_);
delete impl_;
impl_ = tmp_impl;

return *this;
}

void foo::print(void) const
{
std::cout << impl_->field_;
}

int foo::get_field(void) const
{
return impl_->field_;
}

void foo::set_field(int field)
{
impl_->field_ = field;
}


// test_foo.cpp
#include "foo.h"

int main(void)
{
foo f1(3);
foo f2(5);
foo f3(f1);

f1.set_field(9);
f1.print();
f2 = f1;
f1.set_field(f2.get_field());
}


Der er ikke den store forskel. Der er naturligvis en lille forskel i syntax,
men indholdet og performance karakteristik er det samme. Det væsentligste er
at det er vanskelligere at bruge forkert - f.eks. lave en memory-leak.

Der er naturligvis et performance overhead, hvis man bruger denne
fremgangsmåde i forhold til at lave det som een klasse. Det stammer primært
fra at der kræves heap-allokering og man fratager muligheden for at bruge
inline funktioner. Til gengæld får man hurtigere compilering.

>
> En interface definition som i Java ville ikke være nogen dårlig ide, men
> kræver såvidt jeg kan se det en ændring i sproget.
>

Interfaces i Java er en lidt anden størrelse end "pimpl", idet det sigter på
run-time polymophy, baseret på arvehierakier.
Pimpl er typisk til konkrete klasser, som John Lakos antyder i sin
betegnelse.

Venlig hilsen

Mogens Hansen





Jesper Wolf Jesperse~ (28-02-2002)
Kommentar
Fra : Jesper Wolf Jesperse~


Dato : 28-02-02 20:25

Hej Mogens.

"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:a5lnad$2iqg$1@news.cybercity.dk...

> > Desværre kender jeg ikke nogen mulighed for at man i C++ kan skjule en
> > klasses indhold for omverdenen.
>
> Det kan man sagten, og det er et ikke ualmindeligt idiom i C++.
> Det går under forskellige navne:
> * "handle/body" (i Advanced C++, James O. Coplien)
> * "compiler firewall" eller "fully insulated concrete class" (i
> Large-Scale C++ Software Design, John Lakos)
> * "pimpl" (i Exceptional C++, Herb Sutter)
> pimpl er en forkortelse af "Pointer to Implementation".
>
[ snip ]

Tak for eksemplet, jeg har overvejet noget pointer baseret data hiding, men
synes ikke jeg vil betale prisen med henhold til performance og ekstra
arbejde med at skrive og vedligeholde tingene.

Når jeg går i gang med at skrive moduler,bliver første udgave typisk lidt
skitseagtig, og springer let hen over visse ting.
Når så folk ser hvordan tingene er implementeret så benytter de sig af den
information og går ud fra at tingene ikke ændrer sig.
Når jeg så kommer tilbage og skriver noget kode der håndterer det hele og
performer bedre så skal jeg tit til at omskrive de moduler andre folk har
skrevet, fordi de har benytet sig af skitsekodens sideeffekter.

Hvis jeg blot kunne offentliggøre den del af headeren der fortæller folk
hvad de kan regne med og skjuler alt andet, uden at det koster meget ekstra
arbejde ville jeg sansynligvis gøre det.

> Der er ikke den store forskel. Der er naturligvis en lille forskel i
syntax,
> men indholdet og performance karakteristik er det samme. Det væsentligste
er
> at det er vanskelligere at bruge forkert - f.eks. lave en memory-leak.
>
> Der er naturligvis et performance overhead, hvis man bruger denne
> fremgangsmåde i forhold til at lave det som een klasse. Det stammer
primært
> fra at der kræves heap-allokering og man fratager muligheden for at bruge
> inline funktioner. Til gengæld får man hurtigere compilering.

Hurtigere kompilering kunne være rart, men vore dages compiler/maskin
kombinationer er meget hurtigere end de compilere jeg voksede op med. Selv
Borland, der er en sløv sag, performer godt nok når man holder sig fra
IDE'et.

> > En interface definition som i Java ville ikke være nogen dårlig ide, men
> > kræver såvidt jeg kan se det en ændring i sproget.
>
> Interfaces i Java er en lidt anden størrelse end "pimpl", idet det sigter

> run-time polymophy, baseret på arvehierakier.
> Pimpl er typisk til konkrete klasser, som John Lakos antyder i sin
> betegnelse.

Det er muligt at Java's interface definitioner har nogle underliggende
forudsætninger jeg ikke kender.
Det var blot en ide jeg kunne se fornuft i.

Jeg har kørt et projekt igang i C++ under anvendelse af STL og lærebogen
"Accellerated C++" og må sige at det er gået meget bedre end det plejer når
man skal køre noget igang i C.
Jeg kan ikke få alle projektdeltagerne til at gøre alt hvad jeg vil,
fejl/exception håndtering er der ikke mange af dem der fatter hvad er, men
den rå kode har langt færre fejl og færre tilfældige sideeffekter. Så selv
de helt uøvede har faktisk frembragt kode der med lidt efterpudsning kan
bruges til noget.

Vore dages ledere tror at en udvikler er en udvikler, og så sætter de en
"Oracle Forms" haj og en "PL/SQL nørd" til at skrive C++ uden at regne med
at de skal læres op. Desuden bliver de hevet af projektet inden det er
færdigt for der er andre opgaver der haster mere.
I den verden er det rart at man kan give folk en kickstart med bogen
"Accellerated C++" og så skal man helst have et bibliotek af interface
funktioner som de kan bruge til det de skal interface med. Også selv om de
tilgrænsende moduler ikke er færdige.

Derfor har jeg brug for at kunne skrive hurtige skitser, som bare stiller
det basale til rådighed. Men folkene skulle helst ikke benytte sig af det
der foregår bag kulisserne. Det gør de dog ofte når de kan se det i header
filen, de fatter ikke hvorfor de skulle lade være, for de slipper som oftest
lettere om ved et eller andet på den måde. Jeg opdager det ikke før jeg
skriver interfacemodulerne om. Og så sidder jeg selv med oprydningsopgaven
for så er folkene videre på næste projekt.

Her nytter det ikke noget at opfordre til personlig disciplin, for der er
mange personer indblandet, her drejer det sig nærmere om at gøre det lettere
for folkene at gøre tingene rigtigt første gang, eller at forhindre dem i at
opdage hvordan man kan gøre det forkert.

Jeg tror jeg vil kigge lidt på de bøger du foreslår, men det kommer nok til
at vare lidt før jeg kan få tid. Der er som sædvanlig nogle deadlines der er
overskredet

Du og alle de andre der har kommenteret, skal have tak for kommentarer,
eksempler, og henvisninger.

Med venlig hilsen
Jesper Wolf Jespersen


Per Abrahamsen (28-02-2002)
Kommentar
Fra : Per Abrahamsen


Dato : 28-02-02 17:43

Claus Rasmussen <clr@cc-consult.dk> writes:

> En anden god grund til at bruge denne teknik er at man gerne vil undgå
> at de filer, der inkluderer en header fil også kommer til at inkludere
> de filer, som headeren selv ellers ville gøre brug af. Det er gælder
> specielt hvis man bruger STL, hvor man ellers risikerer temmeligt
> lange kompileringstider.

Det kan også få løst op på nogen situationer med gensidig
afhængighed.

> Har du i øvrigt en url på din daisy-dims ?

<http://www.dina.kvl.dk/~daisy/>

Christian Hemmingsen (27-02-2002)
Kommentar
Fra : Christian Hemmingsen


Dato : 27-02-02 18:26

igorr@ifi.uio.no (Igor V. Rafienko) writes:

> > Det forekom mig at det var for mange detaljer at have stående i
> > h-filen. Jeg overvejede om der ikke der kun skulle stå en kort
> > deklaration og så hele erklæringen i implemmentationsfilen, lidt
> > ligesom en funktion.
>
>
> Mnja, det bør du sannsynligvis ikke gjøre av den grunn at dersom det
> eneste som er synlig er en "forward declaration":
>
> struct myarray;
>
> så vil du kunne lage pekere til 'struct myarray', men ikke noe mer. Og
> da er det relativt håpløst å få gjort noe som helst. IMHO.

Siden hvornår er indkapsling gået hen og blevet en dårlig ting?
Selvfølgelig skal han lave metoder til at manipulere/tilgå sin struct,
men der kan der jo være gode grunde til at han ikke ønsker at den
tilgås direkte.


--
Christian Hemmingsen

Per Abrahamsen (28-02-2002)
Kommentar
Fra : Per Abrahamsen


Dato : 28-02-02 14:08

"Mogens Hansen" <mogens_h@dk-online.dk> writes:

> Hvis du vil overtræde private, så gør det dog på en ordenligt, gennemført og
> portabel måde (som John Lakos viser i "Large-Scale C++ Software Design):
>
> #define private public

Er det portabelt? Jeg troede MSVC++ enkodede public/private i data
mangling.

Jeg har selv haft problemer fordi MSVC++ enkoder om man har brugt
"struct" eller "class", så

struct Foo;

// bla bla bla kode der bruger Foo*

class Foo { ... };

ikke virker.

> Iøvrigt ser jeg ikke nogen som helst grund til at C++ skulle beskytte folk,
> der _bevidst_ vil opføre sig tåbeligt!

Enig. Der er dog også en niche for sprog der beskytter mod potentiel
ondsindet kode, f.eks. til brug i web-browsere.

Mogens Hansen (28-02-2002)
Kommentar
Fra : Mogens Hansen


Dato : 28-02-02 15:20


"Per Abrahamsen" <abraham@dina.kvl.dk> wrote
> "Mogens Hansen" <mogens_h@dk-online.dk> writes:
>
> > Hvis du vil overtræde private, så gør det dog på en ordenligt,
gennemført og
> > portabel måde (som John Lakos viser i "Large-Scale C++ Software Design):
> >
> > #define private public
>
> Er det portabelt? Jeg troede MSVC++ enkodede public/private i data
> mangling.

ja - det er preprocessoren der erstatter alle "private" med "public".
Hvis det indgår i name-manglingen skal hele programmet oversættes - men det
er jo sådan set i overensstemmelse med one-definition reglen.

>
> Jeg har selv haft problemer fordi MSVC++ enkoder om man har brugt
> "struct" eller "class", så
>
> struct Foo;
>
> // bla bla bla kode der bruger Foo*
>
> class Foo { ... };
>
> ikke virker.
>

Jeg mener at det _skal_ virke ifølge C++ Standarden.

Venlig hilsen

Mogens Hansen



Per Abrahamsen (28-02-2002)
Kommentar
Fra : Per Abrahamsen


Dato : 28-02-02 14:32

"Jesper Wolf Jespersen" <spam.jwj@ehuset.com.spam> writes:

> Desværre kender jeg ikke nogen mulighed for at man i C++ kan skjule en
> klasses indhold for omverdenen.

Det kan man sagtens, prisen er bare en indirection. Nedenfor er en
header file der definerer definerer en "Time" klasse, uden at røbe
hvad den indholder.

Klassen Time::Implementation er defineret i time.C, og impl bliver
initialiseret i Time's constructor som her:

Time::Time (int y, int m, int md, int h)
: impl (*new Implementation (y, mday2yday (y, m, md), h))
{ }

Time::Time (const Time&t)
: impl (*new Implementation (t.impl))
{ }

Time:Time ()
{
delete &impl;
}

Jeg bruger den teknik for friere at kunne ændre i implementationen af
mine klasser, uden at tvinge de klasser der bruger den til at blive
genoversat. Et af de oprindelige designkrav var at systemet skulle
kunne udvides uden adgang til kildeteksten, men som det kan ses af
licensen er det krav ikke længere relavnt. Det er dog stadig rart at
undgå unødig compilering. Men det er en afvejning, for
hastighedskritiske klasser undgår jeg indirektionen, og accepterer
hyppigere omkompileringer. Et valg nogen sprog mange oo-sprog ikke
tilbyder, der er altid en indirektion.

// time.h -- tick tick
//
// Copyright 1996-2001 Per Abrahamsen and Søren Hansen
// Copyright 2000-2001 KVL.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA


#ifndef TIME_H
#define TIME_H

#include <string>
using namespace std;

class Time
{
// Content.
private:
struct Implementation;
Implementation& impl;

// Extract.
public:
int year () const;
int month () const;
int week () const;
int yday () const;
int mday () const;
int wday () const;      // 0=monday, 6=sunday.
int hour () const;

// Simulate.
public:
void tick_hour (int hours = 1);
void tick_day (int days = 1);

// Convert.
public:
static string month_name (int month);
static string wday_name (int wday);
static int month_number (string name);
static int wday_number (string day);
static int mday2yday (int year, int month, int mday);
static int yday2mday (int year, int yday);
static int yday2wday (int year, int yday); // 0=monday, 6=sunday.
static int yday2month (int year, int yday);
static int yday2week (int year, int yday);

// Test.
static bool leap (int year);
static int month_length (int year, int month);
static bool valid (int year, int month, int mday, int hour = 0);
static int days_between (const Time& first, const Time& last);
static int hours_between (const Time& first, const Time& last);

bool operator== (const Time&) const;
bool operator!= (const Time&) const;
bool operator< (const Time&) const;
bool operator<= (const Time&) const;
bool operator>= (const Time&) const;
bool operator> (const Time&) const;

// Construct.
public:
const Time& operator= (const Time&);
Time (int year, int month, int mday, int hour);
Time (const Time&);
~Time ();
};

#endif // TIME_H

Claus Rasmussen (28-02-2002)
Kommentar
Fra : Claus Rasmussen


Dato : 28-02-02 15:06

Per Abrahamsen wrote:

> Jeg bruger den teknik for friere at kunne ændre i implementationen af
> mine klasser, uden at tvinge de klasser der bruger den til at blive
> genoversat.

En anden god grund til at bruge denne teknik er at man gerne vil undgå
at de filer, der inkluderer en header fil også kommer til at inkludere
de filer, som headeren selv ellers ville gøre brug af. Det er gælder
specielt hvis man bruger STL, hvor man ellers risikerer temmeligt
lange kompileringstider.

Det koster en smule i runtime, men det er en guds gave til programmørerne
hvis det er mange filer, der er tale om.

Har du i øvrigt en url på din daisy-dims ?

-Claus


Morten Boysen (28-02-2002)
Kommentar
Fra : Morten Boysen


Dato : 28-02-02 16:34

"Per Abrahamsen" <abraham@dina.kvl.dk> wrote in message
> using namespace std;

Er dette ikke dårlig praksis i en header, da det medfører, at alle
filer, som også inkluderer headeren automatisk, bruger namespace std?


--
Morten Boysen


Per Abrahamsen (28-02-2002)
Kommentar
Fra : Per Abrahamsen


Dato : 28-02-02 17:34

"Mogens Hansen" <mogens_h@dk-online.dk> writes:

> "Per Abrahamsen" <abraham@dina.kvl.dk> wrote
>> "Mogens Hansen" <mogens_h@dk-online.dk> writes:
>>
>> > Hvis du vil overtræde private, så gør det dog på en ordenligt,
> gennemført og
>> > portabel måde (som John Lakos viser i "Large-Scale C++ Software Design):
>> >
>> > #define private public
>>
>> Er det portabelt? Jeg troede MSVC++ enkodede public/private i data
>> mangling.
>
> ja - det er preprocessoren der erstatter alle "private" med "public".
> Hvis det indgår i name-manglingen skal hele programmet oversættes - men det
> er jo sådan set i overensstemmelse med one-definition reglen.

Hvis man har adgang til kildeteksten til hele programmet bliver
spørgsmålet om måder at snyde adgangsbegrænsningen på endnu mere
uinteressant.

Jeg har selv brugt #define tricket et par gange netop for at _undgå_
at skule omkompilere alt når jeg lige ville teste en ide. Det er
selvfølgelig et så grimt hack at det hører til kategorien "skal
fjernes før end arbejdsdag".

> Jeg mener at det _skal_ virke ifølge C++ Standarden.

GCC havde i hvert fald et tilsvarende problem for mange år siden, og
de rettede det så snart jeg sendet en bug report.

Per Abrahamsen (28-02-2002)
Kommentar
Fra : Per Abrahamsen


Dato : 28-02-02 17:47

"Morten Boysen" <morten.boysen@aub.dk> writes:

> "Per Abrahamsen" <abraham@dina.kvl.dk> wrote in message
>> using namespace std;
>
> Er dette ikke dårlig praksis i en header, da det medfører, at alle
> filer, som også inkluderer headeren automatisk, bruger namespace std?

Jo. Til mit forsvar skal siges at GCC ikke understøttede namespaces
da koden blev skrevet, og ikke namespace std før 3.0. På et eller
andet tidspunkt bør det hele proppes i namespace Daisy, men det har
lav prioritet.

Per Abrahamsen (01-03-2002)
Kommentar
Fra : Per Abrahamsen


Dato : 01-03-02 10:59

"Jesper Wolf Jespersen" <spam.jwj@ehuset.com.spam> writes:

> Hurtigere kompilering kunne være rart, men vore dages compiler/maskin
> kombinationer er meget hurtigere end de compilere jeg voksede op med. Selv
> Borland, der er en sløv sag, performer godt nok når man holder sig fra
> IDE'et.

Du bruger vist ikke STL meget...

> Det er muligt at Java's interface definitioner har nogle
> underliggende forudsætninger jeg ikke kender. Det var blot en ide
> jeg kunne se fornuft i.

De ligner vel mere abstrakte baseclasses end "pimpl" i C++ hvad angår
information hiding.

N/A (28-02-2002)
Kommentar
Fra : N/A


Dato : 28-02-02 15:20



N/A (28-02-2002)
Kommentar
Fra : N/A


Dato : 28-02-02 15:20



N/A (28-02-2002)
Kommentar
Fra : N/A


Dato : 28-02-02 15:20



N/A (28-02-2002)
Kommentar
Fra : N/A


Dato : 28-02-02 15:20



Søg
Reklame
Statistik
Spørgsmål : 177500
Tips : 31968
Nyheder : 719565
Indlæg : 6408514
Brugere : 218887

Månedens bedste
Årets bedste
Sidste års bedste