Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » const

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
09.03.2006, 10:42 Uhr
ref



Das wort const , taucht ab und zu auf, wenn ich const sehe , verstehe ich das das objekt wie
hier in diesem abschnitt , soll nicht geändert werden , oder? , aber wenn ja warum lassen wir
das objekt einfach so ohne anderung und schon das problem ist gelöst , warum schreibt man const ?.

C++:
#include "string.hpp"

// iostream bereits eingebunden

using std::cout; // Diese Datei verwendet std::cout





class Employee

{

public:

     Employee();

     Employee(char *, char *, char *, long);

     ~Employee();

     Employee(const Employee&);

     Employee & operator= (const Employee &);



     const String & GetFirstName() const { return itsFirstName; }

     const String & GetLastName() const { return itsLastName; }

     const String & GetAddress() const { return itsAddress; }

     long GetSalary() const { return itsSalary; }



     void SetFirstName(const String & fName)

         { itsFirstName = fName; }

     void SetLastName(const String & lName)

         { itsLastName = lName; }

     void SetAddress(const String & address)

         { itsAddress = address; }

     void SetSalary(long salary) { itsSalary = salary; }

private:

     String    itsFirstName;

     String    itsLastName;

     String    itsAddress;

     long      itsSalary;

};



--
Man kann ein Problem nicht mit der gleichen Denkweise lösen, mit der es erschaffen wurde. (Albert Einstein)

Dieser Post wurde am 09.03.2006 um 10:46 Uhr von ref editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
09.03.2006, 11:02 Uhr
Pler
Einer von Vielen
(Operator)


Ich glaube, dass ist wirklich nur um sich vor sich selbst zu "schützen".
Vielleicht kann der Compiler auch noch ein bisschen optimieren, wenn man das verwendet. Wobei ich mal davon ausgehe, dass der Compiler auch so erkennen würde, wenn eine Variable ne geaendert wird.

Wie gesagt, es schützt meiner Meinung nach wirklich nur davor, dass nicht aus versehen ein Wert zugewiesen wird. Bzw. der Wert geändert wird.

Beachten muss man es meiner Meinung nach nur, wenn man selber Funktionen schreibt. Dann sollte man als Argument zum Beispiel const char* arg angeben, weil sonst eben keine konstanten Zeichenketten übergeben werden können.
Bsp.:

Code:
ret = funktion( "Hallo Welt" );



Funktioniert IMHO nicht, wenn das argument als char* deklariert ist.


Dieses const:
const String & GetFirstName() const { return itsFirstName; }
hab ich allerdings nich nie gesehen.


Nachtrag:
Habs grad noch mal ausprobiert. Entegegen meinen Behauptungen scheint es doch zu gehen.
Aber ich könnte wetten, dass ich da schon mal Probleme hatte.

Und virtuel schreibt hier leider nur über volatile.
@virual:
Kommt der Artikel zu const noch?

Dieser Post wurde am 09.03.2006 um 11:11 Uhr von Pler editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
09.03.2006, 11:27 Uhr
virtual
Sexiest Bit alive
(Operator)


Zunächstmal kann es ziemlich gefährlich sein, das const fort zulassen. Das prominenteste Beispiel ist folgendes:


C++:
int main() {
    char* hello = "hello";
    hello[0] = 'H';
}


Dieser Code wird bei einigen Platformen das Programm abstürzen lassen, denn eigentlich ist die Deklaration

C++:
    char* hello = "hello";


nur aus historischen Gründen möglich, in wirklichkeit handelt es sich um ein

C++:
    const char* hello = "hello";


weil Stringliterale ("hello") grundsätzlich constant sind.

Auf vielen Platformen stürzt das Programm ab, weil eben der String "hello" bei Programmausfühung in einem Nur-Lese Datensegment abgelegt wird. Analoges wäre theoretisch auf bei jeder Art von anderen Objekten denkbar, aber in der Praxis wird dies selten der Fall sein: denn sieht man von solchen einfachen Strings ab, so ist bei komplexeren Objecten in der Regel ja irgendwelche Initialisierungsarbeit zu erledigen, die es erforderlich macht, daß man erstmal schreiben kann.

Daneben ist die Zusicherung einer Routine/Methode, ein Object nicht zu verändern (eben weil es const ist) ziemlich wichtig in kopmplexeren Beispielen.
zB ist im Source aus dem ersten Post

C++:
Employee(char *, char *, char *, long);


ziemlich problematisch: denn woher soll ein Benutzer der Klasse denn nun wissen, ob der Inhalt der ersten drei parameter verändert wurde? - Jemand, der die Klasse nicht kennt und irgendwelche parameter dort reinsteckt, wird - falls er die ursprünglichen Werte noch braucht - Kopien ziehen müssen.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
09.03.2006, 13:04 Uhr
ao

(Operator)


Ich verändere mal das Beispiel und "verCPlusPlusse" es ein bisschen, dann sieht mans besser, und da ich nicht weiß, was "String" ist, nehme ich std::string.


C++:
#include <string>
#include <iostream>

class Employee
{
private:
    std::string    itsName;
    long        itsSalary;

public:
    Employee(const std::string & rName, long salary)
    : itsName (rName)
    , itsSalary (salary)
    {
    }

    const std::string & Name () const { return itsName; } // name as rvalue only -> name cannot be changed.

    long Salary () const { return itsSalary; }    // salary as rvalue -> this returns the value
    long & Salary () { return itsSalary; }        // salary as lvalue -> this returns a reference and
                                                // lets the value be changed.
};

int main (void)
{
    Employee e ("Dilbert", 10000);

    std::cout << e.Name () << " earns $" << e.Salary () << std::endl;    // Name and Salary used as rvalues

    std::cout << e.Name () << " gets a raise." << std::endl;
    e.Salary () = 12000;                                                // Salary used as lvalue

    std::cout << e.Name () << " earns $" << e.Salary () << std::endl;

    return 0;
}



Output:

Code:
Dilbert earns $10000
Dilbert gets a raise.
Dilbert earns $12000



Erklärungen:

Im Konstruktor sorgt die const-string-Referenz dafür, dass nicht nur echte std::string-Objekte reingereicht werden können

C++:
std::string name = "Seppel";
Employee e (name, 100);


sondern auch alle Datentypen, aus denen ein const-string konstruiert werden kann, zum Beispiel String-Literale

C++:
Employee e ("Hans Mustermann, 1000);

Char-Pointer, Funktionsergebnisse, die char* oder string sind und so weiter. Das macht diesen Konstruktor flexibel, und man muss nicht für jeden dieser Quell-Typen einen eigenen Konstruktor bauen, sondern der eine erschlägt alles. Mit einer Nicht-const-Referenz würde das nicht gehen.

In der Funktion Name () wird das angebundene Employee-Objekt als unveränderlich definiert. Name () kann also nur in Kontexten verwendet werden, in denen der Name abgefragt und nicht neu gesetzt wird (sogenannter "rvalue-Kontext"). Jeder Versuch, etwas wie

C++:
e.Name () = "Wally";

zu machen, führt zum Compilerfehler. Aus Performance-Gründen (Strings können lang sein!) liefert Name () keine Kopie des Wertes, sondern eine Referenz. Diese muss auch wieder const sein, damit sie zu itsName passt: Innerhalb der "Name () const"-Funktion sind alle Member des angebundenen Employee-Objekts implizit const.

Für die erste Version der Funktion Salary () gilt dasselbe, nur auf die Referenz aus Performance-Gründen kann verzichtet werden und stattdessen eine Kopie geliefert werden. Die zweite Version liefert eine Referenz auf itsSalary, und sie trägt kein const-Attribut. Über diese Funktion kann itsSalary verändert werden ("lvalue-Kontext").

Auf diese Weise kann man festlegen, was mit einer Klasse angestellt werden darf und was nicht. Der Benutzer der Klasse kann so nur die vom Entwickler vorgesehenen Aktionen programmieren, es sei denn, er castet irgendwelche const-Modifier mit brutaler Gewalt weg. Dann ist er aber auch selber verantwortlich.

ao
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
09.03.2006, 14:34 Uhr
kronos
Quotenfisch
(Operator)



Zitat von virtual:
[...]denn eigentlich ist die Deklaration

C++:
    char* hello = "hello";


nur aus historischen Gründen möglich[...]


Kann das sein, dass der gcc irgendwo zwischen version 3 und 4 aufgehört das zu unterstützen?
Bin neulich fast verrückt geworden, als ich nach 'nem halben Jahr mal wieder was in C schreiben wollte und er auf einmal in genau dem von dir beschriebenen Fall meinen "alten Programmierstil" boykottiert hat...
--
main($)??<-$<='?'>>2?main($-!!putchar(
(("$;99M?GD??(??/x0d??/a:???;a"+'?'/4)
??($??)+'?'/3-2-1+$%2)??''?')):'?';??>
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
09.03.2006, 14:45 Uhr
Pler
Einer von Vielen
(Operator)


Nö.
Der gibt bei mir nicht mal ein Warning aus.

Aber das ist ja genau das was ich oben gemeint habe (Zuweisung von const char* zu char*.

Jetzt weiß ich aber wieder wo das Problem war.


C++:
// versuch.cpp
#include <iostream>
using namespace std;

void ausgabe( char* );

main( void )
{
        string
                mystring( "Hallo" );

        ausgabe( mystring.c_str() );

        return 0;
}

void ausgabe( char* arg )
{
        cout << arg << endl;
}




bash:

$ make versuch
g++     versuch.cpp   -o versuch
versuch.cpp: In function ‘int main()’:
versuch.cpp:11: error: invalid conversion from ‘const char*’ to ‘char*’
versuch.cpp:11: error:   initializing argument 1 of ‘void ausgabe(char*)’
make: *** [versuch] Error 1



Mit const char* funktioniert das ganze ohne Probleme.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
09.03.2006, 15:01 Uhr
ao

(Operator)



Zitat von Pler:
Mit const char* funktioniert das ganze ohne Probleme.

Genau. Es heißt ja auch

C++:
class string
{
public:
    const char * c_str () const;
};


im Prinzip jedenfalls. Damit sagt die String-Klasse: Die Rückgabe von c_str() darf gelesen werden, aber man soll sie nicht verändern. Die Implementierung von string darf sich darauf verlassen, das niemand das versuchen wird.

C++:
string s ("Hallo");
const char * cp = s.c_str ();
cout << cp; // Lesezugriff, OK
cp[0] = 'X'; // Schreibzugriff, verboten -> Compilerfehler.
char * p = (char *) cp; // gewaltsames Umcasten, Compiler schweigt,
                 // aber ab hier geschieht alles auf eigene Gefahr.
p[0] = 'X'; // Schreibzugriff über p, syntaktisch OK, aber riskant.



Das Reinreichen von mystring.c_str() in ausgabe (char *) ist semantisch dasselbe wie oben. Mit ausgabe (const char *) ist alles im grünen Bereich; ausgabe versichert damit, den Parameter nicht zu verändern.

Wenn die Implementierung von ausgabe () sich nun daran nicht hält, das const wegcastet und im String rumfummelt, gilt genau wie oben "auf eigene Gefahr".

ao

Dieser Post wurde am 09.03.2006 um 15:09 Uhr von ao editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
09.03.2006, 15:10 Uhr
Pler
Einer von Vielen
(Operator)


Ok, ich hab mal noch was ausprobiert. Eigentlich scheint es nie zu gehen. Nur eben bei dieser Initialisierung, die virtual schon oben angesproche hat.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: