Ben Pope said:
Probably simple error checking, or perhaps not, the amount of error
checking is irrelevant if you're encapsulating, right?
I have to agree. Encapsulation should automatically hide these
implementation details. What I think properties are useful for is not just
an excuse for public variables. What I think properties are useful for is to
create simple to use members that have functionality that makes sense in the
context of thier object. Say I have a Clock object with three members Hours,
Minutes Seconds. Using encapsulation rules I would write out
Accessor/Mutator pairs for each variable. If I wanted to add some value to
Minutes then I would create another function to do that, same with Hours and
Seconds. In these new functions I would again use the accessor/mutator
pairs. I always found that in this context, I always end up with functions
that do normal variable routines but use longer function names. What I
suggest is use a "property" so that they "Look" like public variables but
"Behave" in whichever context they are in. I would rather read:
Clock clock(0, 0, 0);
clock.Minutes += 80;
cout << clock.Hours << " : " << clock.Minutes << endl;
output would read : 1 : 20
This just makes sense for a Clock class to do, and I dont have to keep
typing something like clock.addMinutes(80); It just seems more intuitive to
me like this.
I have to disagree. If it looks like a public variable, people will
expect it to behave like one... should what looks like a simple assignment
throw an exception?
Actually, after using java for a while I've grown quite fond of
everything being able to throw an exception. This allows me to create code
that can dynamically fix any mistakes that may crop up and notify me right
away that there is a problem with one of my classes or methods or whatever.
Being ready for exceptions from anywhere is always a good thing in my mind.
And if you consistantly use the function notation, then you are
simplifying the interface.
Simplifying yes, Easier to use, maybe. When creating a class, you have
to watch the length of your member names that you use. If you don't then you
run the risk of losing time writing and rewriting long member names
especially on members that add functionality for private variables as they
are usually used most. I think that if it makes sense then symbols are
better.
Additionally, providing direct access to the members (or appearing to)
doesn't really hide the implementation details.
In a way, it does. Take the Clock example again. If I go clock.Seconds++
and clock.Seconds is already equal to 59 then clock.Seconds++ would set
itself to 0 and do clock.Minutes++ at the same time to simulate a real
clock. Someone using this class knows that this happens they just don't have
to know how it actually happens. They are just glad that it does happen with
no effort on their part.
Having said that:
class Thing {
int property_;
public:
const int& property() const { return property_; }
int& property() { return property_; }
};
class OtherThing {
int property_;
public:
int property() const { return property_; }
void property(int val) { property_ = val; }
};
int main() {
Thing thing;
thing.property() = 4;
int myProperty = thing.property();
OtherThing otherThing;
otherThing.property(4);
int myOtherProperty = otherThing.property();
}
Whats wrong with those two ways of exposing the properties? It's a pretty
simple interface. You don't have to prepend the functions with get & set,
just take advantage of overloading.
Nothing is wrong with any of those, they are valid and easy to read. But
the problem is when you add funtionality what happens whan you want to add
one to your property? you would have to right a function say addProperty(int
val) { property += val; } where as Thing.Property++ or Thing.Property += 1.
is shorter and is still obvious to the user. Also the way you do it, I have
to rewrite the default functionality for each member every time I write a
class. With my template I can have the basic functionality as soon as I
declare it, and extend it as I see fit.