/ 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
Operator overload ?
Fra : Torben W. Hansen


Dato : 22-10-02 14:47

Jeg arbejder med en øvelse der går ud på at sammenligne to elementer fra to
ens objekter ved at benyttes _operator_overload_ . Det er
_operator_overload_ teknikken som jeg ikke helt forstår.

Jeg håber at nogen vil kaste et blik på mit problem. Spørgsmålene står som
kommentarer i kildeteksten nedenfor - på forhånd tak...
Torben W. Hansen


#include <iostream>
#include <string>

class streng
{
public:
streng(char *);
char *operator +(char *);
int operator ==(streng);
void vis_streng(void);
private:
char strengdata[256];
};

streng::streng(char *str)
{
strcpy(strengdata, str);
}

char * streng:erator +(char *str)
{
return(strcat(strengdata, str));
}


int streng:erator ==(streng str) // overload-funktion for "==".
{ // Benyttes i
main().
int i;

for (i=0; strengdata[i]==str.strengdata[i]; i++) //
str.strengdata[i] er parameteroverført,
if ((strengdata[i]=='\0') && (str.strengdata[i]=='\0')) // men hvor får
strengdata[i] sin værdi fra ?
return (1);

return(0);
}

int main(void)
{
int dummy;

streng titel("Jeg programmerer C++!");
streng oevelse("Overload af operatorer");
streng saetning("Jeg programmerer C++!");


// ????????????????????????????????????????????????
// Jeg forstår at objektet "saetning" overføres som
// parameter til "=="-overload-funktion nedenfor,
// men hvordan overføres objektet
// "titel" til overload-funktionen ?
// ????????????????????????????????????????????????
if (titel == saetning)
std::cout << "titel og saetning er ens" << endl;

if (titel == oevelse)
std::cout << "titel og oevelse er ens" << endl;

if (saetning == oevelse)
std::cout << "saetning og oevelse er ens" << endl;

std::cin >> dummy;
}





 
 
Martin Dyring (22-10-2002)
Kommentar
Fra : Martin Dyring


Dato : 22-10-02 16:11

"Torben W. Hansen" <mail@ins-intersoft.com> wrote in message
news:ap3ksf$1jlq$1@news.cybercity.dk...
> // ????????????????????????????????????????????????
> // Jeg forstår at objektet "saetning" overføres som
> // parameter til "=="-overload-funktion nedenfor,
> // men hvordan overføres objektet
> // "titel" til overload-funktionen ?
> // ????????????????????????????????????????????????
> if (titel == saetning)
> std::cout << "titel og saetning er ens" << endl;

Det du i virkeligheden gør er at kalde "titel.operator ==(saetning)", dvs.
du kalder member-funktionen operator == i instansen titel.

Mvh,
Martin Dyring



Torben W. Hansen (22-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 22-10-02 17:09


"Martin Dyring" <mda@image.dk> skrev i en meddelelse
news:MSdt9.158972$Qk5.5785262@news010.worldonline.dk...

> Det du i virkeligheden gør er at kalde "titel.operator ==(saetning)", dvs.
> du kalder member-funktionen operator == i instansen titel.

Ja selvfølgelig - tusind tak Martin...

Kunne man forestille sig at cout og cin benytter samme trick så eksempelvis

std::cout << "Denne streng";

egentlig er noget alá

std::cout .operator <<("Denne streng");

???

Med venlig hilsen
Torben W. Hansen




Martin Dyring (22-10-2002)
Kommentar
Fra : Martin Dyring


Dato : 22-10-02 17:16

"Torben W. Hansen" <mail@ins-intersoft.com> wrote in message
news:ap3t7e$1th3$1@news.cybercity.dk...
> Ja selvfølgelig - tusind tak Martin...
>
> Kunne man forestille sig at cout og cin benytter samme trick så
eksempelvis
>
> std::cout << "Denne streng";

Yeps - det er præcis det samme. :)

--
Mvh,
Martin Dyring





Torben W. Hansen (22-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 22-10-02 17:26

"Martin Dyring" <mda@image.dk> skrev i en meddelelse
news:aOet9.159552$Qk5.5795548@news010.worldonline.dk...

> > std::cout << "Denne streng";
>
> Yeps - det er præcis det samme. :)

TAK - Jeg havde håbet på at 10-øren ville falde for mig , men i dag blev
det nok nærmere 10-kronen !!!

Med venlig hilsen
Torben W. Hansen







Torben W. Hansen (22-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 22-10-02 17:41

Jeg prøvede lige at udskifte

if (titel == saetning)
med
if (titel.operator ==(saetning) )

og

std::cout << "titel og saetning er ens" << endl;
med
std::cout.operator <<("titel og saetning er ens") << endl;

minsandten om ikke compileren åd det hele råt - og så virkede det tillige
....

Med venlig hilsen
Torben W. Hansen




Mogens Hansen (22-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 22-10-02 19:24


"Martin Dyring" <mda@image.dk> wrote in message
news:aOet9.159552$Qk5.5795548@news010.worldonline.dk...
> "Torben W. Hansen" <mail@ins-intersoft.com> wrote in message
> news:ap3t7e$1th3$1@news.cybercity.dk...
> > Ja selvfølgelig - tusind tak Martin...
> >
> > Kunne man forestille sig at cout og cin benytter samme trick så
> eksempelvis
> >
> > std::cout << "Denne streng";
>
> Yeps - det er præcis det samme. :)

Næsten.

Hvis der var skrevet
std::cout << 1;
ville det være
cout.operator<<(1)
der blev kaldt.

Når der står
std::cout << "Denne streng";
er det den globale funktion
ostream& operator<<(cout, "Denne streng");
der bliver kaldt.
(Det er i virkeligheden en template funktion, og ostream er en typedef af en
template klasse - men pyt med det i denne sammenhæng).

For enhver binær operator @, kan x@y enten opfattes som
x.operator@(y) // member function
eller
operator@(x,y) // non-member function

Det er væsentligt, for hvis det altid var en member funktion, ville udvalget
af typer som y kan antage være fastlagt når x er defineret.
Det ville betyde at man ikke ville kan streame egne typer til f.eks. cout,
som
std::cout << streng("Toben W. Hansen's streng-type");

Venlig hilsen

Mogens Hansen



Bjarke Dahl Ebert (23-10-2002)
Kommentar
Fra : Bjarke Dahl Ebert


Dato : 23-10-02 21:22

"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:ap450i$28b6$2@news.cybercity.dk...

> For enhver binær operator @, kan x@y enten opfattes som
> x.operator@(y) // member function
> eller
> operator@(x,y) // non-member function

Ah, ka' de' nu os' pas'?
Det forekommer mig (og MSVC 6.0) at operator= kun kan være en member
function.

Derimod ser MSVC sjovt nok ud til at acceptere en global operator->*.
Det virker absurd - tillader standarden virkelig at man eksternt kan
"forære" en klasse en operator->*?


Mvh. Bjarke





Mogens Hansen (24-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 24-10-02 06:04


"Bjarke Dahl Ebert" <bebert@worldonline.dk> wrote in message
news:3yDt9.170428$Qk5.5950088@news010.worldonline.dk...
> "Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
> news:ap450i$28b6$2@news.cybercity.dk...
>
> > For enhver binær operator @, kan x@y enten opfattes som
> > x.operator@(y) // member function
> > eller
> > operator@(x,y) // non-member function
>
> Ah, ka' de' nu os' pas'?
> Det forekommer mig (og MSVC 6.0) at operator= kun kan være en member
> function.

Ja, strengt taget kan x@y _opfattes_ som enten member eller ikke-member
(§13.5.2).
Men det er rigtigt at operator= (assignment - §13.5.3) og operator()
(function call - §13.5.4) _skal_ implementeres som member-funktion.

>
> Derimod ser MSVC sjovt nok ud til at acceptere en global operator->*.

Ja, det mener jeg.
Ifølge §13.5.1 (Unary operator):
A prefix unary operator shall be implemented by a non-static member function
(9.3) with no parameters or a non-member function with one parameter. Thus,
for any prefix unary operator @, @x can be interpreted as
either x.operator@() or operator@(x). If both forms of the operator function
have been declared, the rules in 13.3.1.2 determine which, if any,
interpretation is used.

> Det virker absurd - tillader standarden virkelig at man eksternt kan
> "forære" en klasse en operator->*?

Det drejer sig vel om "hvad er en klasse og hvad er en del af dens interface
?".

I den glimrende bog
Exceptional C++
Herb Sutter
ISBN 0-201-61562-2
item 32, side 122-130, er der en glimrende gennemgang af det ikke trivielle
spørgsmål.


Venlig hilsen

Mogens Hansen





Bjarke Dahl Ebert (24-10-2002)
Kommentar
Fra : Bjarke Dahl Ebert


Dato : 24-10-02 23:55

"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:ap7uqk$jnh$1@news.cybercity.dk...
> "Bjarke Dahl Ebert" <bebert@worldonline.dk> wrote in message

> > Derimod ser MSVC sjovt nok ud til at acceptere en global operator->*.
> Ja, det mener jeg.
> Ifølge §13.5.1 (Unary operator):

->* er skam en binær operator.

> > Det virker absurd - tillader standarden virkelig at man eksternt kan
> > "forære" en klasse en operator->*?
> Det drejer sig vel om "hvad er en klasse og hvad er en del af dens
interface
> ?".

Ja, men netop '->*' (ligesom '=') synes jeg logisk set virker som noget en
klasse selv skal definere - dvs. en del af klassens interface.
På den anden side kan jeg heller ikke se at der skulle ske de store ulykker
ved at nogen definerer en "ekstern" operator ->*.

Mvh. Bjarke





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


Dato : 25-10-02 17:55



"Bjarke Dahl Ebert" <bebert@worldonline.dk> wrote in message
news:<cU_t9.175263$Qk5.6075353@news010.worldonline.dk>...

[8<8<8<]
> ->* er skam en binær operator.

Ja.
Jeg læste ikke dit indlæg grundigt nok.
Jeg læste det som "operator->"

> Ja, men netop '->*' (ligesom '=') synes jeg logisk set virker som
> noget en klasse selv skal definere - dvs. en del af klassens
> interface.

Det er væsentligt at en klasses interface er mere end hvad der er defineret
i selve klassen (altså rundt regnet member-funktionerne).


Venlig hilsen

Mogens Hansen




Mogens Hansen (22-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 22-10-02 19:24

Du får lige en håndfuld kommentarer, ud over det konkrete spørgsmål.

"Torben W. Hansen" <mail@ins-intersoft.com> wrote in message
news:<ap3ksf$1jlq$1@news.cybercity.dk>...

[8<8<8<]
> #include <string>

Du vil formodentlig have adgang til std::strcpy og std::strcat.
Så hedder det
#include <cstring>

#include <string>
er for at få adgang til klassen std::string

>
> class streng
> {
> public:
> streng(char *);

Har string constructoren tænkt sig at ændre på den tekst, der bliver givet
med som argument ?
Hvis ikke kan man skrive:
streng(const char*);
^^^^^

> char *operator +(char *);

Ditto her

char *operator +(const char *);
^^^^^

> int operator ==(streng);

Den bør returnere en bool.
Enten har de 2 strenge samme værdi, ellers har de forskellig værdi.
Så får vi:
bool operator==(streng);
^^^^

Funktionen ændrer (formodentlig) ikke på selve objektet.
Så får vi:
bool operator==(streng) const;
^^^^^
Som du har skrevet det, overføres parameteren by-value, og der bliver derfor
lavet en kopi.
Det er mere effektivt at overføre parameteren by-value, og samtidig love at
man ikke ændrer den
Så får vi:
bool operator(const streng&) const;
^^^^^ ^

> void vis_streng(void);

Den ændrer formodentlig heller ikke på selve objektet.
Altså
void vis_streng() const;
^^^^^

> private:
> char strengdata[256];
> };
>
> streng::streng(char *str)
> {
> strcpy(strengdata, str);

Det hedder egentlig std::strcpy

> }
>
> char * streng:erator +(char *str)
> {
> return(strcat(strengdata, str));

Og det samme her: std::strcat

> }
>
>
> int streng:erator ==(streng str) // overload-funktion for "==".
> { // Benyttes i
main().
> int i;
>
> for (i=0; strengdata[i]==str.strengdata[i]; i++) //
str.strengdata[i] er parameteroverført,
> if ((strengdata[i]=='\0') && (str.strengdata[i]=='\0')) // men hvor får
strengdata[i] sin værdi fra ?

Du er inde i en member-funktion.
Derfor har adgang til data for eet bestemt objekt.
Der findes en underforstået funktions-parameter som hedder "this". Det er en
peger til det aktuelle objekt.
Der er ingen forskel på om man kalder streng:erator== eller streng::equal
(hvis en sådan eksisterede). Det er rent syntaktisk.

Et par generelle småting:
Det er normal at foretrække at bruge size_t til at adressere et array med.
Så er man sikker på at den er stor nok til at adressere hele array.
Desuden er der ikke nogen grund til at bruge en type, der kan antage
negative værdier.

Det er at foretrække at erklære og initialisere variable samtidig, hvis det
er muligt.

Det er at foretrække at bruge ++i frem for i++.
++i returnerer den inkrementerede værdi.
i++ returnerer den oprindelige værdi, hvilket betyder at den skal gemmes i
en variabel som så kan returneres.
Konkret spiller det formodentlig ikke nogen rolle, men hvis det er en mere
kompleks iterator kan der være lidt at spare.

Noget der af og til hjælper mig, er at skrive konstante ting på venstre side
af ==.
Altså
'\0' == strengdata[i]
Fidusen er at, hvis man glemmer at skrive to =, bliver
'\0' = strengdata[i]
til en fejl som compileren finder, mens
strengdata[i] = '\0'
bliver en runtime fejl, som man selv skal finde.

Den dobbelt test "(strengdata[i]=='\0') && (str.strengdata[i]=='\0')" er
overflødig, fordi vi på det sted _ved_ at
"strengdata[i]==str.strengdata[i]".


> return (1);
>
> return(0);
> }

Altså (jeg håber ikke der er tryk-fejl - det er ikke compileret)
bool streng:erator==(const streng& rhs) const
{
for(size_t i = 0; strengdata[i] == rhs.strengdata[i]; ++i)
if('\0' == strengdata[i])
return true;
return false;
}

Man _kunne_ også have skrevet operator== som en ikke member-funktion (se
eventuelt også mit andet indlæg):

<ikke compileret kode>

class streng
{
// ...
private:
friend bool operator==(const streng&, const streng&);
char strengdata[256];
};

bool operator==(const streng& lhs, const streng& rhs)
{
for(size_t i = 0; lhs.strengdata[i] == rhs.strengdata[i]; ++i)
if('\0' == lhs.strengdata[i] return true;
return false;
}

</ikke compileret kode>

og have brugt det på præcis samme måde.
I den situation er det nemt at se, hvor de 2 objekter kommer fra.
Den genererede kode vil formodentlig være fuldstændig identisk, uanset om
det er en member-funktion eller ej.

Venlig hilsen

Mogens Hansen



Torben W. Hansen (22-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 22-10-02 19:42

"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:ap450a$28b6$1@news.cybercity.dk...
> Du får lige en håndfuld kommentarer, ud over det konkrete spørgsmål.

Tak Mogens - jeg skal lige have pløjet mig igennem dine fyldige svar... (jeg
er jo stadig en ydmyg nybegynder)

Men jeg nåede lige at observere, at jeg ikke har styr på _namespace_ ,
hvilket du aldeles ret i - jeg sidder stadig med "Kris Jamsa" - har endnu
ikke modtaget "Accelerated C++".

Med venlig hilsen
Torben W. Hansen



Byrial Jensen (22-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 22-10-02 20:02

Mogens Hansen <mogens_h@dk-online.dk> skrev:

> Et par generelle småting:
> Det er normal at foretrække at bruge size_t til at adressere et array med.
> Så er man sikker på at den er stor nok til at adressere hele array.
>
> Desuden er der ikke nogen grund til at bruge en type, der kan antage
> negative værdier.
>
> Det er at foretrække at erklære og initialisere variable samtidig, hvis det
> er muligt.
>
> Det er at foretrække at bruge ++i frem for i++.

Sikke mange kommentarer til brugen af en variabel. Jeg ville nok
foretrække en variant helt uden "i", men med pointere i stedet. Så
behøver man ikke spekulere på typen:

// Ikke oversat kode
bool streng:erator == (const streng& rhs) const
{
for (const char * p_lhs = strengdata, * p_rhs = rhs.strengdata ;
* p_lhs == * p_rhs ; ++ p_lhs, ++ p_rhs)
if (! * plhs)
return true;
return false;
}

Men der er ingen grund til at skrive indholdet i funktionen selv.
Det findes allerede i standard-biblioteket:

// Ikke oversat kode
bool streng:erator == (const streng& rhs) const
{
return ! std::strcmp (strengdata, rhs.strengdata);
}

--
Skal musik- og edb-industrien have ret til fratage forbrugerne deres
rettigheder i henhold til Ophavsretloven, begrænse konkurrencen og
fremme monopoldannelse ved hjælp af tekniske midler? Sig nej! Nu!
Støt underskriftsindsamlingen på http://www.digitalforbruger.dk

Mogens Hansen (22-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 22-10-02 22:08


"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:slrnarb7tg.21r.bjensen@ask.ask...

[8<8<8<]
> Men der er ingen grund til at skrive indholdet i funktionen selv.
> Det findes allerede i standard-biblioteket:

Man behøves slet ikke at lave streng klassen, for std::string findes i
standard-biblioteket - altså hvis det ikke lige var for øvelsens skyld

Venlig hilsen

Mogens Hansen



Mogens Hansen (22-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 22-10-02 22:10


"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:slrnarb7tg.21r.bjensen@ask.ask...

[8<8<8<]
> Men der er ingen grund til at skrive indholdet i funktionen selv.
> Det findes allerede i standard-biblioteket:

Man behøves slet ikke at lave streng klassen, for std::string findes i
standard-biblioteket - altså hvis det ikke lige var for øvelsens skyld

Venlig hilsen

Mogens Hansen





Byrial Jensen (23-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 23-10-02 06:18

Mogens Hansen <mogens_h@dk-online.dk> skrev:
> "Byrial Jensen" <bjensen@nospam.dk> wrote in message
>
>> Men der er ingen grund til at skrive indholdet i funktionen selv.
>> Det findes allerede i standard-biblioteket:
>
> Man behøves slet ikke at lave streng klassen, for std::string findes i
> standard-biblioteket - altså hvis det ikke lige var for øvelsens skyld

Det er selvfølgelig rigtigt, men når der bruges strcpy og strcat,
kunne man synes at der også skal bruges strcmp. Eller at alle 3
skal implementeres fra bunden af.

--
Skal musik- og edb-industrien have ret til fratage forbrugerne deres
rettigheder i henhold til Ophavsretloven, begrænse konkurrencen og
fremme monopoldannelse ved hjælp af tekniske midler? Sig nej! Nu!
Støt underskriftsindsamlingen på http://www.digitalforbruger.dk

Bertel Lund Hansen (22-10-2002)
Kommentar
Fra : Bertel Lund Hansen


Dato : 22-10-02 21:23

Mogens Hansen skrev:

>Altså (jeg håber ikke der er tryk-fejl - det er ikke compileret)
>bool streng:erator==(const streng& rhs) const
>{
> for(size_t i = 0; strengdata[i] == rhs.strengdata[i]; ++i)
> if('\0' == strengdata[i])
> return true;
> return false;
>}

Er det rigtigt? Løkken kører så vidt jeg kan se til der findes en
forskel, og den kan da godt findes præcis på den første strengs
nulterminering?

Det kan også være at løkken kører en million gange selv om
strengene er ens og ganske korte - hvis det affald der ligger
lige bagefter tilfældigvis også er ens.

Jeg ville mene at man er nødt til at sætte en grænse for i (eller
pointeren hvis man bruger Byrials løsning):

for (size_t i = 0; strengdata[i]; ++i)
if(strengdata[i] != rhs.strengdata[i]) return false;
return true;

Eller er der noget jeg har overset?

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

Mogens Hansen (22-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 22-10-02 22:10


"Bertel Lund Hansen" <nospam@lundhansen.dk> wrote in message
news:dpcbru00ir7256ck4murvb7jm0jbie5bbb@news.telia.dk...
> Mogens Hansen skrev:
>
> >Altså (jeg håber ikke der er tryk-fejl - det er ikke compileret)
> >bool streng:erator==(const streng& rhs) const
> >{
> > for(size_t i = 0; strengdata[i] == rhs.strengdata[i]; ++i)
> > if('\0' == strengdata[i])
> > return true;
> > return false;
> >}
>
> Er det rigtigt?

Den forekommer mig at være rigtigt.

> Løkken kører så vidt jeg kan se til der findes en
> forskel,

ja.

> og den kan da godt findes præcis på den første strengs
> nulterminering?

ja.
Og hvis de 2 strenge ikke er nultermineret på samme indeks (altså har samme
længde) vil funktionen returnere false.

>
> Det kan også være at løkken kører en million gange selv om
> strengene er ens og ganske korte - hvis det affald der ligger
> lige bagefter tilfældigvis også er ens.

Nej, løkken kan ikke køre en million gange, hvis de 2 strenge er korte og
ens.
Funktionen vil _altid_ returnere senest når den møder den første
nulterminering i mindst een af strengene.
Der vil entel gælde
strengdata[i] == rhs.strengdata[i] == '\0
så funktionen returner true
eller
(strengdata[i] == '\0' && rhs.strengdata[i] != '\0') || (strengdata[i] !=
'\0' && rhs.strengdata[i] == '\0')
hvilket medfører at
strengdata[i] != rhs.strengdata[i]
hvilket gør at for-løkken afsluttes og funktionen returnerer false.


(Jeg antager at "streng" objektet er initialiseret med en almindelig
nul-termineret streng (der er mindre end hvad der er plads til i
"strengdata" - det er kun en øvelse).
Det betyder at "strengdata" for ethvert "streng" objekt er nul-termineret.
Det er vi vist enige om.
)

>
> Jeg ville mene at man er nødt til at sætte en grænse for i (eller
> pointeren hvis man bruger Byrials løsning):
>
> for (size_t i = 0; strengdata[i]; ++i)
> if(strengdata[i] != rhs.strengdata[i]) return false;
> return true;

Her vil man kunne adressere efter nultermineringen i rhs.strengdata, hvis
strlen(strengdata) > strlen(rhs.strengdata).
Det går naturligvis fint i det konkrete tilfælde, fordi sizeof(strengdata)
== sizeof(rhs.strengdata) == 256, men i en lidt mere realistisk
streng-klasse er strengdata dynamisk allokeret med en størrelse der passer
til opgaven.
I det tilfælde vil algoritmen ikke virke.

> Eller er der noget jeg har overset?

Det tror jeg (ellers har jeg ).
Eller kan du komme med test-data (uden buffer overrun), der får det til at
fejle ?

Venlig hilsen

Mogens Hansen



Bertel Lund Hansen (22-10-2002)
Kommentar
Fra : Bertel Lund Hansen


Dato : 22-10-02 22:21

Mogens Hansen skrev:

>> Er det rigtigt?
>Den forekommer mig at være rigtigt.

Ja, nu kan jeg godt se det.

>> Jeg ville mene at man er nødt til at sætte en grænse for i (eller
>> pointeren hvis man bruger Byrials løsning):

>> for (size_t i = 0; strengdata[i]; ++i)
>> if(strengdata[i] != rhs.strengdata[i]) return false;
>> return true;

>Her vil man kunne adressere efter nultermineringen i rhs.strengdata

Nej. Hvis den når 0 i rhs, er enten de to tegn forskellige, og
den returnerer falsk, eller de er ens, og den afbryder og
returnerer sand.

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

Mogens Hansen (22-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 22-10-02 22:29


"Bertel Lund Hansen" <nospam@lundhansen.dk> wrote in message
news:a2gbru4q58i0l1v8u461tmgt711scif256@news.telia.dk...

> Nej. Hvis den når 0 i rhs, er enten de to tegn forskellige, og
> den returnerer falsk, eller de er ens, og den afbryder og
> returnerer sand.

Ja, selvfølgelig.
Det er samme situation - farven har bare en anden lyd

Venlig hilsen

Mogens Hansen



Bertel Lund Hansen (22-10-2002)
Kommentar
Fra : Bertel Lund Hansen


Dato : 22-10-02 22:45

Bertel Lund Hansen skrev:

>Nej. Hvis den når 0 i rhs, er enten de to tegn forskellige, og
>den returnerer falsk, eller de er ens, og den afbryder og
>returnerer sand.

Beklager, jeg tog fejl. Min løkke terminerer *før* den får testet
det sidste tegn. Den var ellers så dejlig kompakt ...
Denne her virker:

size_t i;
for (i = 0; strengdata[i]; ++i)
if (strengdata[i] != rhs.strengdata[i]) return false;
return strengdata[i] == rhs.strengdata[i];

(Denne her gang har jeg kompileret det for at være sikker).

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

Jens Christian Larse~ (22-10-2002)
Kommentar
Fra : Jens Christian Larse~


Dato : 22-10-02 22:23



Jesper Wolf Jesperse~ (22-10-2002)
Kommentar
Fra : Jesper Wolf Jesperse~


Dato : 22-10-02 22:54

Hej Mogens.

"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:ap450a$28b6$1@news.cybercity.dk...

> bool streng:erator==(const streng& rhs) const
> {
> for(size_t i = 0; strengdata[i] == rhs.strengdata[i]; ++i)
> if('\0' == strengdata[i])
> return true;
> return false;
> }

Der er faktisk flere problemer med ovenstående kode.
For det første afsluttes sammenligningen ikke ved streng afslutningen, men
fortsættes indtil der konstateres en forskel.
1) En sammenligning af en streng med sig selv giver helt uvægerligt en core
dump da du på et eller andet tidspunkt kommer til at ramme adresser du ikke
har adgang til.
2) En kort streng og en lang streng med samme indhold op til afslutningen
sammenlignes som ens, hvis den korte streng står til venstre, men
forskellige hvis den står til højre.
(Der findes implementeringer af strcmp der har samme besynderlige adfærd som
i 2, men jeg synes stadigt det er forkert, visual C++ er enig .

Dette er ikke en kritik af din indsats i nyhedsgruppen, jeg synes bare jeg
ville påpege det.

Jeg har lavet et minimalt eksempel der efter min mening både er til at læse
og gør arbejdet rigtigt, med en fornuftig optimizer vil det endda performe
godt
Koden er skrevet og testet i MSVC 6.


-----

#include <iostream>

const size_t Chunck=32;

class streng
{
const char * data;
public:
streng(const char *input)
{
data=input;
};
bool operator == (const streng & rhs) const
{
bool equal = true;
bool stop = false;
for(const char *c1=data, *c2=rhs.data; equal && !stop; c1++,c2++)
{
equal=(*c1==*c2);
stop = ('\0' == *c1) || ('\0' == *c2);
}
return equal;
};
bool ens (const streng & rhs) const
{
return 0==strcmp(data,rhs.data);
};
};

streng titel ("Jeg programmerer C++!");
streng oevelse ("Overload af operatorer");
streng saetning ("Jeg programmerer C++!");
streng saetning2("Jeg programmerer C++! og bruger lange strenge");

int main(int argc, char* argv[])
{
char dummy;
if (titel == saetning)
std::cout << "titel og saetning er ens" << std::endl;
if (titel == saetning2)
std::cout << "titel og saetning2 er ens" << std::endl;

if (titel == oevelse)
std::cout << "titel og oevelse er ens" << std::endl;

if (saetning == oevelse)
std::cout << "saetning og oevelse er ens" << std::endl;

// gad vide om strcmp er enig i min tolkning

if (titel.ens(saetning))
std::cout << "titel og saetning er ens ifølge strcmp" << std::endl;

if (titel.ens(saetning2))
std::cout << "titel og saetning2 er ens ifølge strcmp" << std::endl;

if (saetning2.ens(titel))
std::cout << "saetning2 og titel er ens ifølge strcmp" << std::endl;

std::cin >> dummy;

return 0;
}
----

Med venlig hilsen
Jesper Wolf Jespersen



Bertel Lund Hansen (22-10-2002)
Kommentar
Fra : Bertel Lund Hansen


Dato : 22-10-02 23:11

Jesper Wolf Jespersen skrev:

>> bool streng:erator==(const streng& rhs) const
>> {
>> for(size_t i = 0; strengdata[i] == rhs.strengdata[i]; ++i)
>> if('\0' == strengdata[i])
>> return true;
>> return false;
>> }

>Der er faktisk flere problemer med ovenstående kode.

Men færre end man lige skulle tro.

>For det første afsluttes sammenligningen ikke ved streng afslutningen, men
>fortsættes indtil der konstateres en forskel.

Det troede jeg også. Men den returnerer senest når strengdata[i]
er 0, og før hvis der findes en forskel.

>1) En sammenligning af en streng med sig selv giver helt uvægerligt en core
>dump

Nej.

>2) En kort streng og en lang streng med samme indhold op til afslutningen
>sammenlignes som ens, hvis den korte streng står til venstre, men
>forskellige hvis den står til højre.

Nej. Når der findes to forskellige tegn, terminerer løkken uden
at teste for 0, og der returneres falsk.

Den er faktisk god nok.

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

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


Dato : 23-10-02 00:17


"Jesper Wolf Jespersen" <oz8ace@qsl.net.spam> wrote in message
news:3db5c974$0$3360$edfadb0f@dspool01.news.tele.dk...
> Hej Mogens.
>
> "Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
> news:ap450a$28b6$1@news.cybercity.dk...
>
> > bool streng:erator==(const streng& rhs) const
> > {
> > for(size_t i = 0; strengdata[i] == rhs.strengdata[i]; ++i)
> > if('\0' == strengdata[i])
> > return true;
> > return false;
> > }
>
> Der er faktisk flere problemer med ovenstående kode.

Har du test-data som du har prøvet og som påviser de formodede problemer ?

> For det første afsluttes sammenligningen ikke ved streng afslutningen, men
> fortsættes indtil der konstateres en forskel.
> 1) En sammenligning af en streng med sig selv giver helt uvægerligt en
core
> dump da du på et eller andet tidspunkt kommer til at ramme adresser du
ikke
> har adgang til.

Nej.
Prøv det.

> 2) En kort streng og en lang streng med samme indhold op til afslutningen
> sammenlignes som ens, hvis den korte streng står til venstre, men
> forskellige hvis den står til højre.

Nej.
Prøv det

[8<8<8<]
> Dette er ikke en kritik af din indsats i nyhedsgruppen, jeg synes bare jeg
> ville påpege det.

Du er velkommen.
Hvis jeg skriver noget sludder, så bør det korrigeres.

Venlig hilsen

Mogens Hansen



Jesper Wolf Jesperse~ (23-10-2002)
Kommentar
Fra : Jesper Wolf Jesperse~


Dato : 23-10-02 18:30

Hej Mogens.

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

> > > bool streng:erator==(const streng& rhs) const
> > > {
> > > for(size_t i = 0; strengdata[i] == rhs.strengdata[i]; ++i)
> > > if('\0' == strengdata[i])
> > > return true;
> > > return false;
> > > }
> >
> > Der er faktisk flere problemer med ovenstående kode.
>
> Har du test-data som du har prøvet og som påviser de formodede problemer ?

Nej og nu jeg læser koden igen er problemet der ikke, jeg har vist
underforstået et semikolon efter løkken. Testen for nul er jo i løkken og
vil terminere løkken korrekt.

Undskyld at jeg overfaldt dig

>> Dette er ikke en kritik af din indsats i nyhedsgruppen, jeg synes bare
jeg
> > ville påpege det.
>
> Du er velkommen.
> Hvis jeg skriver noget sludder, så bør det korrigeres.

Tjah det gjorde du åbenbart ikke alligevel, det lader til at jeg var for
hurtig på aftrækkeren.
Men jeg foretrækker nu alligevel min udgave, den er lettere at læse .

I gamle dage kunne det gøre en stor forskel i performance hvordan man skrev
sin kode, og det at udregne to booleans og så bruge dem i løkken ville være
en del dyrere end blot at skrive koden som du gør.

I den tids compilere ville man forøvrigt altid implementere en sådan rutine
med pointere da en array operation var dyrere end en pointer operation.

I netbsd hvor koden jo er godt optimeret ser en strcmp således ud.
----
int
strcmp(s1, s2)
   register const char *s1, *s2;
{
   while (*s1 == *s2++)
      if (*s1++ == 0)
         return (0);
   return (*(const unsigned char *)s1 - *(const unsigned char *)--s2);
}
---
Denne rutine minder om din implementering, den er bare skrevet i K&R C og
udtaler sig om større eller midre end istedet for bare forskellig.

Jeg tror ikke der vil være megen forskel i den genererede maskinkode for dit
eksempel, mit eksempel og netbsd koden ved anvendelse af en af vore dages
compilere.

Med venlig hilsen
Jesper Wolf Jespersen



Byrial Jensen (23-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 23-10-02 06:18

Jesper Wolf Jespersen <oz8ace@qsl.net.spam> skrev:
>
> 2) En kort streng og en lang streng med samme indhold op til afslutningen
> sammenlignes som ens, hvis den korte streng står til venstre, men
> forskellige hvis den står til højre.
> (Der findes implementeringer af strcmp der har samme besynderlige adfærd som
> i 2, men jeg synes stadigt det er forkert, visual C++ er enig .

Som forklaret af andre har koden vi har set her i gruppen, ikke den
adærd.

Hvilke implementationer af strcmp lider af den beskrevne fejl? Det
lyder ærlig talt underligt hvis en så simpel og hyppigt brugt
funktion skulle have den fejl, for jeg ville tro at det ville blive
opdaget stort set øjeblikkeligt af brugerne.

Du tænker vel ikke på strncmp? Nedenstående kald skal returnere 0
fordi strengene er ens inden for de første 4 tegn:

strncmp ("test", "test2", 4)

--
Skal musik- og edb-industrien have ret til fratage forbrugerne deres
rettigheder i henhold til Ophavsretloven, begrænse konkurrencen og
fremme monopoldannelse ved hjælp af tekniske midler? Sig nej! Nu!
Støt underskriftsindsamlingen på http://www.digitalforbruger.dk

Torben W. Hansen (23-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 23-10-02 11:22

"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:ap450a$28b6$1@news.cybercity.dk...

>Næsten.
>For enhver binær operator @, kan x@y enten opfattes som
> x.operator@(y) // member function
OK

>eller
> operator@(x,y) // non-member function
Ikke forstået - formodentlig da jeg ikke er langt nok indlæringsforløbet
(templates, STL osv.)

>Det er væsentligt, for hvis det altid var en member funktion, ville
udvalget
>af typer som y kan antage være fastlagt når x er defineret.
>Det ville betyde at man ikke ville kan streame egne typer til f.eks. cout,
>som std::cout << streng("Toben W. Hansen's streng-type");
Ikke forstået - af samme årsag som ovenfor

> Du vil formodentlig have adgang til std::strcpy og std::strcat.
> Så hedder det
> #include <cstring>
OK

> Har string constructoren tænkt sig at ændre på den tekst, der bliver givet
> med som argument ?
> Hvis ikke kan man skrive:
> streng(const char*);
> ^^^^^
Mener du at det pointeren peger på bliver erklæret konstant ?

> > int operator ==(streng);
> Den bør returnere en bool.
OK


> Funktionen ændrer (formodentlig) ikke på selve objektet.
> Så får vi:
> bool operator==(streng) const;
> ^^^^^
Hvad er det egentlig der erklæres konstant her ?

> Som du har skrevet det, overføres parameteren by-value, og der bliver
derfor
> lavet en kopi.
> Det er mere effektivt at overføre parameteren by-value, og samtidig love
at
> man ikke ændrer den
> Så får vi:
> bool operator(const streng&) const;
> ^^^^^ ^
Betyder dette en reference til et konstant objekt af klassen streng ?


> > strcpy(strengdata, str);
> Det hedder egentlig std::strcpy
OK - namespace igen

> > if ((strengdata[i]=='\0') && (str.strengdata[i]=='\0')) >
> Du er inde i en member-funktion.
> Derfor har adgang til data for eet bestemt objekt.
OK

> Der findes en underforstået funktions-parameter som hedder "this". Det er
en
> peger til det aktuelle objekt.
Mener du "this.strengdata[i]" ?

> Der er ingen forskel på om man kalder streng:erator== eller
streng::equal
> (hvis en sådan eksisterede). Det er rent syntaktisk.
OK


> Et par generelle småting:
> Det er normal at foretrække at bruge size_t til at adressere et array med.
> Så er man sikker på at den er stor nok til at adressere hele array.
> Desuden er der ikke nogen grund til at bruge en type, der kan antage
> negative værdier.
OK

> Det er at foretrække at erklære og initialisere variable samtidig, hvis
det
> er muligt.
Hvorfor ?

> Det er at foretrække at bruge ++i frem for i++.
> ++i returnerer den inkrementerede værdi.
> i++ returnerer den oprindelige værdi, hvilket betyder at den skal gemmes i
> en variabel som så kan returneres.
Er årsagen til i++ bruger en variabel, at "i" kan evalueres før den
inkrementeres ?

> Noget der af og til hjælper mig, er at skrive konstante ting på venstre
side
> af ==. Altså '\0' == strengdata[i]
Jeg kender problemet - meget snedig metode

> Den dobbelt test "(strengdata[i]=='\0') && (str.strengdata[i]=='\0')" er
> overflødig, fordi vi på det sted _ved_ at
> "strengdata[i]==str.strengdata[i]".
Rigtig godt set - en observation som satte gang i denne tråd hvad ?

> Man _kunne_ også have skrevet operator== som en ikke member-funktion
> class streng
> {
> // ...
> private:
> friend bool operator==(const streng&, const streng&);
> char strengdata[256];
> };
> og have brugt det på præcis samme måde.
> I den situation er det nemt at se, hvor de 2 objekter kommer fra.
Ikke forstået - formodentlig da jeg ikke er langt nok indlæringsforløbet
(Arv, friends osv...)

Der gav du en amatør kam til håret - men tak alligevel...

Med venlig hilsen
Torben W. Hansen








Byrial Jensen (23-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 23-10-02 19:25

Torben W. Hansen <mail@ins-intersoft.com> skrev:
> "Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
>
>>Næsten.
>>For enhver binær operator @, kan x@y enten opfattes som
>> x.operator@(y) // member function

> OK

>>eller
>> operator@(x,y) // non-member function

> Ikke forstået - formodentlig da jeg ikke er langt nok indlæringsforløbet
> (templates, STL osv.)

Jeg prøver lige at forklare med mine ord. Det har ikke noget at
gøre med hverken templates eller STL.

Når du bruger en binær operator @ mellem to operander:

x @ y

vil oversætteren ud fra operandernes typer prøve at finde en
operator-funktion som den kan kalde. Det kan være en funktion som
er defineret i den klasse som x tilhører (en medlemsfunktion).

Det kan også være en fritstående global funktion som ikke er
defineret i nogen klasse (en ikke-medlems-funktion). I så fald er
det blot en almindelig funktion som tager 2 argumenter som
type-mæssigt passer til x og y.

>>Det er væsentligt, for hvis det altid var en member funktion, ville
> udvalget
>>af typer som y kan antage være fastlagt når x er defineret.
>>Det ville betyde at man ikke ville kan streame egne typer til f.eks. cout,
>>som std::cout << streng("Toben W. Hansen's streng-type");

> Ikke forstået - af samme årsag som ovenfor

std::cout er et objekt af typen ostream. (Nej, i virkeligheden er
typen meget mere kompliceret med brug af templates, men det er ikke
vigtigt her). Du kan ikke skrive en ny medlemsfunktion for den
type.

Derimod kan du skrive en ikke-medlemsfunktion som tager 2
argumenter:

ostream& operator<< (ostream out, const streng& str);

>> Har string constructoren tænkt sig at ændre på den tekst, der bliver givet
>> med som argument ?
>> Hvis ikke kan man skrive:
>> streng(const char*);
>> ^^^^^

> Mener du at det pointeren peger på bliver erklæret konstant ?

Ja. Det angives constructoren ikke vil det som pointeren peger på.
Det har stor dokumentationsværdi, og det betyder at der kan
konstrueres streng-objekter ud fra eksisterende pointere til const
char, hvilket man ikke ellers kan.

>> Funktionen ændrer (formodentlig) ikke på selve objektet.
>> Så får vi:
>> bool operator==(streng) const;
>> ^^^^^

> Hvad er det egentlig der erklæres konstant her ?

Det erklæres at funktionen ikke vil ændre det aktuelle objekt, dvs.
det objekt som står på venstresiden af operatoren og som "this"
peger på. Uden den erklæring kan med ikke bruge ==-operatoren til
at sammeligne streng-objekter som er erklæret const.

>> Som du har skrevet det, overføres parameteren by-value, og der bliver
>> derfor
>> lavet en kopi.
>> Det er mere effektivt at overføre parameteren by-value, og samtidig love
>> at
>> man ikke ændrer den
>> Så får vi:
>> bool operator(const streng&) const;
>> ^^^^^ ^

> Betyder dette en reference til et konstant objekt af klassen streng ?

En konstant reference til et objekt af klassen streng. Objektet som
der refereres til, behøver ikke at være konstant, men det må ændres
gennem (ved brug af) referencen.

>> > if ((strengdata[i]=='\0') && (str.strengdata[i]=='\0')) >
>> Du er inde i en member-funktion.
>> Derfor har adgang til data for eet bestemt objekt.
> OK
>
>> Der findes en underforstået funktions-parameter som hedder "this". Det er
>> en
>> peger til det aktuelle objekt.
> Mener du "this.strengdata[i]" ?

"this" er en pointer. Det objekt som den peger på, er "*this".
Datafelter i objektet kan nås ved at bruge:

this->strengdata[i]

som er det samme som   

strengdata[i]

>> Det er at foretrække at erklære og initialisere variable samtidig, hvis
>> det
>> er muligt.

> Hvorfor ?

- For at undgå at kalde en default constructor ved erklæringen
hvis der er tale om objekter.
- For at gøre variablens scope så lille som muligt. Det nedsætter
risikoen for fejl ved brugen og gør det nemmere for oversætteren
at optimere.

>> Det er at foretrække at bruge ++i frem for i++.
>> ++i returnerer den inkrementerede værdi.
>> i++ returnerer den oprindelige værdi, hvilket betyder at den skal gemmes i
>> en variabel som så kan returneres.

> Er årsagen til i++ bruger en variabel, at "i" kan evalueres før den
> inkrementeres ?

Når der er tale om simple tal, og når man ikke bruger værdien af
udtrykket, er der næppe nogen forskel i praksis.

Men i princippet vil "++ i" for typen T udføre denne funktion:

T& T:erator++()
{
*this += 1;
return *this;
}

Og "i ++" vil kalde denne funktion:

const T T:erator(int unused)
{
const T old = *this;
++ *this;
return old;
}

Den ekstra variabel som Mogens omtaler, er den som jeg har kaldt
"old" i funktionen herover. Det ubrugte funktionsargument tjener
til at skelne den fra fra præfiks-funktionen.

>> Man _kunne_ også have skrevet operator== som en ikke member-funktion
>> class streng
>> {
>> // ...
>> private:
>> friend bool operator==(const streng&, const streng&);
>> char strengdata[256];
>> };
>> og have brugt det på præcis samme måde.
>> I den situation er det nemt at se, hvor de 2 objekter kommer fra.

> Ikke forstået - formodentlig da jeg ikke er langt nok indlæringsforløbet
> (Arv, friends osv...)

Måske hjælper det at se en definition af ikke-medlemsfunktionen,
evt. sammen med forklaringerne herover:

bool operator== (const streng& lhs, const streng& rhs)
{
return 0 == std::strcmp (lhs.strengdata, rhs.strengdata);
}

--
Skal musik- og edb-industrien have ret til fratage forbrugerne deres
rettigheder i henhold til Ophavsretloven, begrænse konkurrencen og
fremme monopoldannelse ved hjælp af tekniske midler? Sig nej! Nu!
Støt underskriftsindsamlingen på http://www.digitalforbruger.dk

Byrial Jensen (23-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 23-10-02 19:33

Byrial Jensen <bjensen@nospam.dk> skrev:

Der sneg sig et meningsforstyrrende skrivefejl gennem korrekturen ...

>> Mener du at det pointeren peger på bliver erklæret konstant ?
>
> Ja. Det angives constructoren ikke vil det som pointeren peger på.

Læs: ikke vil /ændre/ det som ...


>> Betyder dette en reference til et konstant objekt af klassen streng ?
>
> En konstant reference til et objekt af klassen streng. Objektet som
> der refereres til, behøver ikke at være konstant, men det må ændres
> gennem (ved brug af) referencen.

Læs: det må /ikke/ ændres gennem referencen.

--
Skal musik- og edb-industrien have ret til fratage forbrugerne deres
rettigheder i henhold til Ophavsretloven, begrænse konkurrencen og
fremme monopoldannelse ved hjælp af tekniske midler? Sig nej! Nu!
Støt underskriftsindsamlingen på http://www.digitalforbruger.dk

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


Dato : 23-10-02 21:04


"Torben W. Hansen" <mail@ins-intersoft.com> wrote in message
news:ap5t87$12vk$1@news.cybercity.dk...
> "Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
> news:ap450a$28b6$1@news.cybercity.dk...
>
> >Næsten.
> >For enhver binær operator @, kan x@y enten opfattes som
> > x.operator@(y) // member function
> OK
>
> >eller
> > operator@(x,y) // non-member function
> Ikke forstået - formodentlig da jeg ikke er langt nok indlæringsforløbet
> (templates, STL osv.)

Hvis har 2 streng objekter
streng str1("blabla");
streng str2("blbl");
og skriver
if(str1 == str2)

så kan det enten være member-funktionen
bool streng:erator==(const streng&) const

eller en ikke-member funktion (en global funktion)
bool operator==(const streng&, const streng&)

der kaldes - afhængigt af hvad der findes.

Man kan så spørge om det er ligegyldigt om det er en member-funktion eller
ej.
I det konkret tilfælde vil det nok være at foretrække at det ikke er en
member-funktion pga. af symetri.

Det vil være tilladt at skrive
if(str1 == "blib")
altså sammenligne et streng objekt med en string literal uanset om
operator== er member-funktion eller ej.
Derimod er det kun tilladt at skrive
if("blib" == str1)
hvis operator== er en ikke-member funktion.

[8<8<8<]
> > Der findes en underforstået funktions-parameter som hedder "this". Det
er
> en
> > peger til det aktuelle objekt.
> Mener du "this.strengdata[i]" ?

ja.
(bortset fra this er en pointer og ikke en reference, så:
this->strengdata[i])

[8<8<8<]
> > Det er at foretrække at erklære og initialisere variable samtidig, hvis
> det
> > er muligt.
> Hvorfor ?

Bl.a. fordi man slipper for at bøvle med ikke initialiserede variable.

Venlig hilsen

Mogens Hansen



Torben W. Hansen (25-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 25-10-02 09:43

"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:ap6v68$2cti$1@news.cybercity.dk...

Tak for besvarelserne, som jeg har arbejdet en del med .

> > >For enhver binær operator @, kan x@y enten opfattes som
> > > x.operator@(y) // member function
> > >eller
> > > operator@(x,y) // non-member function

> Hvis har 2 streng objekter
> streng str1("blabla");
> streng str2("blbl");
> og skriver
> if(str1 == str2)
>
> så kan det enten være member-funktionen
> bool streng:erator==(const streng&) const
OK - altså x.operator@(y) - member function ligesom oprindelige eksempel

> eller en ikke-member funktion (en global funktion)
> bool operator==(const streng&, const streng&)
> der kaldes - afhængigt af hvad der findes.
OK - altså operator@(x,y) - non-member function noget i retning af
nedenstående, hvor jeg efter bedste evne har indført dine anbefalinger :

#include <iostream> // KODE START
#include <string>

class streng
{
public:
streng(char *);
void vis_streng(void);
//private: // Er ikke indkapslet - "operator == funktion" bør erklæres som
friend til streng ?"
char strengdata[256];
};

streng::streng(char *str)
{
std::strcpy(strengdata, str);
}

bool operator ==(const streng& str1, const streng& str2) //
overload-funktion for "==".
{
// Global non-member-funktion.

for (int i=0; str1.strengdata[i] == str2.strengdata[i]; i++) //
str1.strengdata[i] og
if (str1.strengdata[i]=='\0') //
str2.strengdata[i] er
return true;
// begge parameteroverført.
return false;
}

int main(void)
{
streng titel("Jeg programmerer C++!");
streng oevelse("Overload af operatorer");
streng saetning("Jeg programmerer C++!");

if (titel == saetning) // opfattes som "if (operator ==(titel, saetning))"
std::cout << "titel og saetning er ens" << std::endl;

if (titel == oevelse)
std::cout << "titel og oevelse er ens" << std::endl;
} // KODE SLUT

> Man kan så spørge om det er ligegyldigt om det er en member-funktion eller
> ej. I det konkret tilfælde vil det nok være at foretrække at det ikke er
en
> member-funktion pga. af symetri.
OK

> Det vil være tilladt at skrive
> if(str1 == "blib")
> altså sammenligne et streng objekt med en string literal uanset om
> operator== er member-funktion eller ej.
> Derimod er det kun tilladt at skrive
> if("blib" == str1)
> hvis operator== er en ikke-member funktion.

Det med at sammenligne et streng objekt med en string literal ramte du noget
som Byrial flittigt har forsøgt at forklare mig andet steds i denne tråd.
(I dit eksempel går jeg ud fra at "blib" overføres via en af de to parametre
der er af klassen streng - altå en tildeling).

Byrial, som sikkert har helt ret i det han siger, nævnte noget om
konvertering via constructoren , men jeg kan ikke gennemskue hvad
constructor skulle have at gøre med dit eksempel _if("blib" == str1)_ eller
med eksemplet med Byrial, (objekt = char *).

Hvordan kan en _string literal_ eller _char *_ tildeles et objekt, da et
objekt vel er en samling af kode og data, og hvordan i så fald kan objektet
vide hvor det skal gøre af _string literal_ eller _char *_ ?

Med venlig hilsen
Torben W. Hansen












Mogens Hansen (26-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 26-10-02 13:45


"Torben W. Hansen" <mail@ins-intersoft.com> wrote in message
news:apb06r$pk8$1@news.cybercity.dk...

[8<8<8<]
> streng(char *);

En lille ting:
streng(const char*)

> void vis_streng(void);

Lidt mere const-correctnes igen:
void vis_streng() const;

[8<8<8<]
> Det med at sammenligne et streng objekt med en string literal ramte du
noget
> som Byrial flittigt har forsøgt at forklare mig andet steds i denne tråd.
> (I dit eksempel går jeg ud fra at "blib" overføres via en af de to
parametre
> der er af klassen streng - altå en tildeling).

Når man skriver:
if(str1 == "blib")
vil compileren prøve at finde en passende "operator==".
Det kan være som member-funktion til streng eller som non-member.
Den vil først se om den kan finde en der passer eksakt.
Det vil sige, enten
bool streng:erator(const char*) const;
eller
bool operator==(const streng&, const char*);
men de findes ikke (det vil være helt lovligt at skrive dem, og der vil
muligvis være en performance gevist).
Derefter vil compileren se om den kan lave en implicit konvertering, så den
kan finde en passende "operator==".

En constructor, der ikke er erklæret "explicit", og som tager een parameter
vil kunne lave en implicit konvertering.
Det betyder at constructoren
streng::streng(const char*)
vil kunne tage en streng literal og lave et streng objekt ud af det. Når det
så er sket kan compileren bruge enten
bool streng:erator==(const streng&);
eller
bool operator==(const streng&, const streng&)
og bruge til sammenligningen.

Compileren laver altså en implicit konvertering, hvorved der bliver oprettet
et temporært object af typen streng.
Compileren skriver altså
if(str1 == "blib")
om til
if(str1 == streng("blib"))


Venlig hilsen

Mogens Hansen



Torben W. Hansen (29-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 29-10-02 12:03


"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:ape2j2$180r$1@news.cybercity.dk...


Tak for svaret...

> Når man skriver:
> if(str1 == "blib")
> vil compileren prøve at finde en passende "operator==".
> Det kan være som member-funktion til streng eller som non-member.
> Den vil først se om den kan finde en der passer eksakt.
> Det vil sige, enten
> bool streng:erator(const char*) const;
> eller
> bool operator==(const streng&, const char*);
> men de findes ikke (det vil være helt lovligt at skrive dem, og der vil
> muligvis være en performance gevist).
> Derefter vil compileren se om den kan lave en implicit konvertering, så
den
> kan finde en passende "operator==".
>
> En constructor, der ikke er erklæret "explicit", og som tager een
parameter
> vil kunne lave en implicit konvertering.
> Det betyder at constructoren
> streng::streng(const char*)
> vil kunne tage en streng literal og lave et streng objekt ud af det. Når
det
> så er sket kan compileren bruge enten
> bool streng:erator==(const streng&);
> eller
> bool operator==(const streng&, const streng&)
> Compileren skriver altså
> if(str1 == "blib")
> om til
> if(str1 == streng("blib"))

Kan man tænke sig at compiler finder på en eller anden måde vælger en
forkert funktion til konverteringen ?

--
Med venlig hilsen
Torben W. Hansen




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


Dato : 29-10-02 18:49


"Torben W. Hansen" <mail@ins-intersoft.com> wrote in message
news:aplpr7$2ns$1@news.cybercity.dk...

[8<8<8<]
> Kan man tænke sig at compiler finder på en eller anden måde vælger en
> forkert funktion til konverteringen ?

Man kan forestille sig at der er flere mulige konverteringer til rådighed.
I så fald vil compileren brokke sig over ambiguity.

Venlig hilsen

Mogens Hansen



Torben W. Hansen (29-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 29-10-02 18:54


"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:apmhi9$10gm$2@news.cybercity.dk...
> Man kan forestille sig at der er flere mulige konverteringer til rådighed.
> I så fald vil compileren brokke sig over ambiguity.
OK - og tak.
Så fik jeg det endelig på plads...

Med venlig hilsen
Torben W. Hansen



Torben W. Hansen (22-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 22-10-02 19:26

Jeg sidder med endnu en øvelse der går ud på at tilføje en streng til et
streng-element ved at benytte _operator_overload_ .

For mig ser det ud som om man tildeler en char-pointer til et objekt ved
navn "titel" - kan man det ?
Hvis man endelig vil refererer til "titel", er den ufuldstændige reference
"titel" så ikke adressen på objektet, der vel nødvendigvis ikke er en
pointer til char ?

På forhånd tak...
Torben W. Hansen


#include <iostream>
#include <string>

class streng
{
public:
streng(char *);
char *operator +(char *);
void vis_streng(void);
private:
char strengdata[256];
};

streng::streng(char *str)
{
strcpy(strengdata, str);
}

char * streng:erator +(char *str)
{
return(strcat(strengdata, str));
}

void streng::vis_streng(void)
{
std::cout << strengdata << endl;
}


int main(void)
{
int dummy;

streng titel("Jeg programmerer C++!");
titel.vis_streng();

//?????????????????????????????????????????????????????????????????
// Udtrykket nedenfor, titel + " Det er jeg glad for", returnerer en
// pointer til char, der tildeles titel.
// Hvilken mening giver det at titel, der et object, tildeles
// en pointer til char ?
//?????????????????????????????????????????????????????????????????
titel = titel + " Det er jeg glad for";
titel.vis_streng();

// Jeg er klar over at det i virkligheden er nok at skrive:
// titel + " Det er jeg glad for"; men øvelsen er det lavet som ovenfor.

std::cin >> dummy;
}



Byrial Jensen (22-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 22-10-02 20:19

Torben W. Hansen <mail@ins-intersoft.com> skrev:
> Jeg sidder med endnu en øvelse der går ud på at tilføje en streng til et
> streng-element ved at benytte _operator_overload_ .
>
> For mig ser det ud som om man tildeler en char-pointer til et objekt ved
> navn "titel" - kan man det ?

Ja, det kan man fordi der findes en constructor for streng som tager
en char * som argument. Der laves et nyt sreng-objekt ved at kalde den
constructor, hvorefter det resulterede objekt tildeles til "titel".

(Advarsel: Ovenstående er min forståelse, men jeg er også nybegynder
udi C++).

> Hvis man endelig vil refererer til "titel", er den ufuldstændige reference
> "titel" så ikke adressen på objektet, der vel nødvendigvis ikke er en
> pointer til char ?

"titel" er navnet på et objekt. "&titel" er adressen på objektet.

--
Skal musik- og edb-industrien have ret til fratage forbrugerne deres
rettigheder i henhold til Ophavsretloven, begrænse konkurrencen og
fremme monopoldannelse ved hjælp af tekniske midler? Sig nej! Nu!
Støt underskriftsindsamlingen på http://www.digitalforbruger.dk

Torben W. Hansen (23-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 23-10-02 10:31

"Byrial Jensen" <bjensen@nospam.dk> skrev i en meddelelse
news:slrnarb948.23t.bjensen@ask.ask...

> > For mig ser det ud som om man tildeler en char-pointer til et objekt ved
> > navn "titel" - kan man det ?
>
> Ja, det kan man fordi der findes en constructor for streng som tager
> en char * som argument. Der laves et nyt sreng-objekt ved at kalde den
> constructor, hvorefter det resulterede objekt tildeles til "titel".
Det kan godt være at du har svaret på mit spørgsmål, jeg kan bare ikke
rigtig fange pointen - så jeg prøver at stille spørgsmålet på en anden måde,
altså problemet er sætningen:

titel = titel + " Det er jeg glad for";
^^^ ^^^^^^^^^^^^^^^^^^^^
1 2

udtryk 1 er et object ,pga. streng titel("Jeg programmerer C++!");
udtryk 2 er en char * ,pga. char * streng:erator +(char
*str){..}

dvs. at der faktisk står: object = char *
^^^^^ ^^^^
1 2

For at ovenstående skal give mening skal object vel være af typen char * ?
Hvordan er object blevet til typen char * ?
Jeg opfatter object (titel) som at være af klassen streng og ikke typen char
* ?
Hvori består min misforståelse ?

Med venlig hilsen
Torben W. Hansen


> (Advarsel: Ovenstående er min forståelse, men jeg er også nybegynder
> udi C++).
OK- men jeg synes nu du klarer dette meget godt...

> "titel" er navnet på et objekt. "&titel" er adressen på objektet.
Det jeg skrev var noget vrøvl - Jeg bildte mig et øjeblik ind, ligesom en
ufuldstændig array-reference er adressen til første element i arrayet (array
= &array[0] ), at det samme gjorde sig gældende ved strukturer og objekter.





Byrial Jensen (23-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 23-10-02 19:25

Torben W. Hansen <mail@ins-intersoft.com> skrev:
> "Byrial Jensen" <bjensen@nospam.dk> skrev i en meddelelse
>
>> > For mig ser det ud som om man tildeler en char-pointer til et objekt ved
>> > navn "titel" - kan man det ?
>>
>> Ja, det kan man fordi der findes en constructor for streng som tager
>> en char * som argument. Der laves et nyt sreng-objekt ved at kalde den
>> constructor, hvorefter det resulterede objekt tildeles til "titel".

> Det kan godt være at du har svaret på mit spørgsmål, jeg kan bare ikke
> rigtig fange pointen - så jeg prøver at stille spørgsmålet på en anden måde,
> altså problemet er sætningen:
>
> titel = titel + " Det er jeg glad for";
> ^^^ ^^^^^^^^^^^^^^^^^^^^
> 1 2

(Du bør bruge en fastbreddeskrift når laver markeringer med ^^^ i
linjen nedenunder. Som det er nu, kan vi kun gætte på hvad der er
markeret, da vi ikke kender bredderne i den proportionalskrift som
du brugte da du skrev teksten).

> udtryk 1 er et object ,pga. streng titel("Jeg programmerer C++!");
> udtryk 2 er en char * ,pga. char * streng:erator +(char
> *str){..}
>
> dvs. at der faktisk står: object = char *
> ^^^^^ ^^^^
> 1 2
>
> For at ovenstående skal give mening skal object vel være af typen char * ?
> Hvordan er object blevet til typen char * ?

streng-objektet er ikke blevet til typen "char *". Det er lige
omvendt: Pointeren til char bliver konverteret til "streng" før
tildelingen. Konvertering sker ved hjælp af den constructor-funktion
for en streng som tager en "char *" som argument, og efter
konvertering tildeles det nylavede streng-objekt til variablen
titel.

> Jeg opfatter object (titel) som at være af klassen streng og ikke typen char
> * ?

Korrekt.

> Hvori består min misforståelse ?

Det er højresiden af tildelingsoperatoren som ændrer type, ikke
venstre-siden.

--
Skal musik- og edb-industrien have ret til fratage forbrugerne deres
rettigheder i henhold til Ophavsretloven, begrænse konkurrencen og
fremme monopoldannelse ved hjælp af tekniske midler? Sig nej! Nu!
Støt underskriftsindsamlingen på http://www.digitalforbruger.dk

Torben W. Hansen (23-10-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 23-10-02 22:25


"Byrial Jensen" <bjensen@nospam.dk> skrev i en meddelelse
news:slrnardmut.18u.bjensen@ask.ask...

> (Du bør bruge en fastbreddeskrift når laver markeringer med ^^^ i
> linjen nedenunder. Som det er nu, kan vi kun gætte på hvad der er
> markeret, da vi ikke kender bredderne i den proportionalskrift som
> du brugte da du skrev teksten).
Det havde jeg ikke tænkt på - men det er taget til efterretning

> streng-objektet er ikke blevet til typen "char *". Det er lige
> omvendt: Pointeren til char bliver konverteret til "streng" før
> tildelingen. Konvertering sker ved hjælp af den constructor-funktion
> for en streng som tager en "char *" som argument, og efter
> konvertering tildeles det nylavede streng-objekt til variablen
> titel.

Tak for svaret...

Her er udsnit fra tidligere fremsendte kildetekst

// kald til "constructor funktion"
streng titel("Jeg programmerer C++!"); titel.vis_streng(); // (1.)
....

// kald til "operator overload funktion"
titel = titel + " Det er jeg glad for"; titel.vis_streng(); // (2.)

Jeg er med på at "constructor funktion" putter char*- argumentet ("Jeg
programmerer C++!") ind i det af constructor nyoprettede streng-objekt
(titel).
Men mener du virkelig at kaldet (2.) til "operator overload funktion"
ovenfor også gør brug af "constructor funktion" til konvertering fra char *
til streng ?
Jeg troede at kun "constructor funktion" blev anvendt ved erklæring af
objektet (1.) og ikke ved efterfølgende kald til andre af objektets
funktioner, i dette tilfælde "operator overload funktion".

Med venlig hilsen
Torben W. Hansen



JS (22-10-2002)
Kommentar
Fra : JS


Dato : 22-10-02 20:22


"Torben W. Hansen" <mail@ins-intersoft.com> wrote in message
news:ap3ksf$1jlq$1@news.cybercity.dk...

> class streng
> {
> public:
> streng(char *);
> char *operator +(char *);
> int operator ==(streng);
> void vis_streng(void);
> private:
> char strengdata[256];
> };
>
> streng::streng(char *str)
> {
> strcpy(strengdata, str);
> }
>

Nu er det måske mest noget eksempel kode inde i klassen da din øvelse var
Operator overload, men alligevel :

Har du overvejet hvad der sker hvis en af de strenge du fodrer klassen med
er længere end størrelsen på strengdata, eller hvis den slet ikke er
nul-termineret ??

Jeg bruger altid noget i denne retning :
...
...
const size_t MAX_STRING_LENGTH = 256;

...
...
char strengdata[MAX_STRING_LENGTH + 1];

...
...
strncpy(strengdata, str, MAX_STRING_LENGTH);
strengdata[MAX_STRING_LENGTH] = '\0';


og tilsvarende strncat i stedet for strcat..


Alt sammen gode grunde til at bruge string i stedet for char arrays.



mvh/JS







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

Månedens bedste
Årets bedste
Sidste års bedste