> On the other hand... 99.999% of the code that uses iostream sticks to the simplified interface
> and does not need to concern itself with those getters/setters.
Formatted I/O relies on a bunch of getters and setters provided by the stream:
setf,
unsetf,
precision,
width,
fill
And getters and setters to facilitate handling and reporting of I/O errors:
clear,
rdstate,
setstate,
exceptions
Granted, the getter and setter for
exceptions is not all that common.
But 99.999% of the code that uses iostream does not need to format output or handle input errors?
Hmm.. So all the code that I've seen belongs to the minority 0.001%. One lives, and one learns.
> So yes... I would say iostream is not fully encapsulated...
The rest of the standard library is even worse:
smart pointers: as if
get and
reset /
operator= were not enough, they also have
release.
std::vector<> and friends: These are so badly designed that their entire interface consists of getters and setters.
...
Designed by a bunch of idiots who do not understand encapsulation 101.
They needed to have been clearly told: 'Getters/setters go against (you could even say they completely destroy) the encapsulation mindset'
> If I write hundreds of lines of code where I use X() and Y() members to access the point data...
> then all of the sudden the underlying code changes on me and now all of those calls start calling
> multiple trig functions to convert behind my back... my program's performance will be destroyed.
Performance is not governed by number of lines of code; it is governed by how many times a particular piece of code is executed. For instance, there needs to be just one line of code executed in a tight loop, that incrementally rotates the points that were set in an animation.
Encapsulation means that the users can still think of points as entities in a cartesian co-ordinate system, irrespective of the internal implementation details.
Encapsulation does not mean: no getters or setters; take it from me, they completely destroy encapsulation.
> I think the important thing is to understand the benefits of getters/setters and then to evaluate whether a particular
> circumstance will benefit from them. If it won't benefit then don't do it.
Yes. +1
> There are compelling reasons for private class members and appropriate getters and setters.
+1 to that too.
> This is a bad class. It is not encapsulated, and those getters/setters have absolutely no value at all.
This is a good class. It is encapsulated, it has getters and setters, those getters/setters have value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
class Record
{
private:
string name;
string company;
int age;
public:
int getAge() { return age; }
void setAge(int v) { if( age < 0 ) throw std::logic_error("negative age") ; age = v; }
string getName() { return name; }
void setName(string v) { if( v.empty() ) throw std::logic_error("name can't be empty()"); name = v; }
// ...
};
|
Tip: Use encapsulation (yes, encapsulation may involve providing getters and/or setters) if there are invariants to be established. Either right now, or if they may come into reckoning later, as the design evolves.
The quote from Stroustrup's 'The C++ Programming Language' in an earlier post gives the rationale.