PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : const-correctness bei get-Methoden



miracoli
19-06-2009, 08:54
Hi,

mir stellt sich gerade die Frage welche Art und Weise der Deklaration einer get-Methode denn überhaupt die sinnvollste ist.

Um das ganz mal zu konkretisieren: Folgende, hier vereinfachte, Klasse:



class Shape {

private:
Color color;

protected:
Shape( Color const& _color) : color(_color) {}
virtual ~Shape() {}
virtual void draw() const = 0;

public:

void setColor(const Color & _color) { color = _color; }

//Hier nun die Frage welche die richtige ist
Color & getColor() { return color; }
const Color* getColor() { return &color; }
const Color* getColor() const { return &color; }
const Color* const getColor() { return &color; }
const Color* const getColor() const { return &color; }
const Color & getColor() const { return color; }
const Color& getColor() { return color; }
};

get-Methoden sollten ja eigentlich das Objekt nicht verändern, von dem Gesichtspunkt aus hätte ich

const Color & getColor() const { return color; } genommen. Andererseits kann ich dann folgendes nichtmehr machen:

s->getColor().setR(255);Von daher würde ich denhier nehmen:
Color & getColor() { return color; }Allerdings kann ich mit dem dann wiederum in der draw()-Methode einer Abgeleiteten Klasse nicht getColor() aufrufen, weil draw() ja const ist und von daher dürfen keine nicht-const Methoden aufgerufen werden. Man könnte color in Shape auch public oder protected machen .... Ich bin im Moment total verwirrt. Wär echt toll wenn jemand Licht ins Dunkle bringen könnte.

anda_skoa
19-06-2009, 12:06
Je nach Komplexität eines Color Objekts würde ich eher sogar so schreiben
(so wird das zum Beispiel auch durchgehend bei Qt gemacht)


Color color() const { return color; }

sonst


const QColor& color() const { return color; }


Und nachdem das eine abstrakte Klasse ist, color eher protected.
Private bringt IMHO nur was, wenn damit eine wesentliche Invariante gesichert werden muss, die Entwickler von abgeleiteten Klassen eventuell nicht ganz richtig hinbekommen könnten.

Der von dir angesprochene Anwendungsfall des direkten Methodenaufrufs am Memberobjekt ist zwar bequem, man muss dabei aber berücksichtigen, dass solche Änderungen an der umschließenden Klasse vorbei gehen.
D.h. Shape bzw. eine Subklasse könnten auf eine etwaige Wertänderung nicht reagieren, weil sie ja nix davon mitkriegen.

Ich persönlich mache das daher nur dann, wenn das optionale Einstellungen sind, die zu einem bestimmten bekannten Zeitpunkt ausgewertet werden.
Beipiel


class HttpRequest
{
protected:
MetaData m_MetaData;

public:
MetaData& metaData() { return m_metaData;}

istream get() const; // nur get() benutzt die Werte von MetaData
};


Ciao,
_

miracoli
19-06-2009, 14:51
Ok, d.h. bei einfacher Komplexität:


Color color() const { return color; }

bei höherer Komplexität:


const QColor& color() const { return color; }

Richtig?
Und

s->getColor().setR(255);

würde dann ja nichtmehr gehen, also nurnoch


s->setColor(255, s->getColor()->getG(), s->getColor()->setB());

wodurch das Shape-Objekt (bzw. Objekt einer Subklasse) wieder die Kontrolle über die Änderungen erhält.
Habe ich dich soweit richtig verstanden?

Grüße

anda_skoa
19-06-2009, 17:22
Ok, d.h. bei einfacher Komplexität:


Color color() const { return color; }

bei höherer Komplexität:


const QColor& color() const { return color; }

Richtig?

Korrekt.



Und

s->getColor().setR(255);

würde dann ja nichtmehr gehen, also nurnoch


s->setColor(255, s->getColor()->getG(), s->getColor()->setB());

wodurch das Shape-Objekt (bzw. Objekt einer Subklasse) wieder die Kontrolle über die Änderungen erhält.
Habe ich dich soweit richtig verstanden?


Ja, oder


Color color = s->getColor();
color.setR(255);
s->setColor(color);


Ciao,
_

miracoli
19-06-2009, 19:48
Vielen Dank!

Gruß

panzi
19-06-2009, 23:04
Je nach Komplexität eines Color Objekts würde ich eher sogar so schreiben
(so wird das zum Beispiel auch durchgehend bei Qt gemacht)


Color color() const { return color; }


Ja, aber weil viele (komplexe) Klassen in Qt das hier verwenden:
http://doc.qtsoftware.com/4.5/qshareddatapointer.html

Damit kann man implizite smart Pointer implementieren die eine copy-on-write Semantik verwenden. D.h. kopierst du ein solches Objeckt machst du in Wirklichkeit nur eine Kopie eines Pointer (+ref-count erhöhen). Erst bei der nächsten Schreiboperation wird tatsächlich eine Kopie erstellt. Wenn es nie eine solche gibt hat man natürlich den vorteil das auch nix Kopiert wird.