[Exceptional C++ Style] Item 17 - Encapsulation

Jon Jagger jon at jaggersoft.com
Mon Dec 20 11:26:41 EST 2004


solosnake . wrote:

>> From: Jon Jagger <jon at jaggersoft.com>
>> >compared to what? here's a grammar_definition object...
>>
>> grammar_definition js;
>>
>> >and an example of using it (to get at one of the const data members) 
>> is...
>>
>> const non_terminal_definition & x = js.if_statement;
>>
>> >compared to getting at it via an accessor...
>>
>> const non_terminal_definition & x = js.if_statement();
>>
>> >how is the dependency any different?
>>
>
> Hello
>
> Are we debating as to which of these two following classes is the best 
> to use? Ignoring your specific implementation, which may as a special 
> case justify the design decisions you took, I am arguing that there is 
> no advantage to public (but const) member data, and that there are 
> real disadvantages.

But do not seem to have said what the disadvantages are yet...

>
> // Case 1 : Encapsulated data.
> class Case1
> {
> public:
>    const SomeData& GetSomeData()const;
> private:
>    const someData_;
> };

And I'm afraid this example does not convince me. This is not 
encapsulated data. Sorry but it isn't. It's data that starts hidden but 
then makes a break for it and escapes (returned by reference from 
method). The net result is you have code that could be said to somewhat 
encourage a dangerous style. Viz...

const SomeData & all_bets_are_off()
{
    Case1 c;
    return c.GetSomeData();
}


>
> // this could also be inlined instead.
> const SomeData& Case1::GetSomeData()const
> {
>    return someData_;
> }
>
> // Case 2 : public const data.
> class Case2
> {
> public:
>    const someData_;
> };
>
> Is there really an argument for case 2? Case 1 allows all the 
> functionality required for any usage of case 2, but is safer, 

Is it? See above. If the method had returned by value, then things might 
have been different, but it doesn't...Look at what you have written - a 
class with one public const data member and no, repeat no, member 
functions at all. Case2 is a struct in disguise. Now you might, quite 
legitmately, say but that's just an example, that you wouldn't write 
that in real code. That in real code you would have some member 
functions. And I'd agree. And ask for the real example so we can ground 
this a bit.

Don't get me wrong now. I'm all for encapsulation. For example, size() 
is a method on the STL containers and that's right and proper. No one is 
suggesting that size should be a public (non-const) data member. 
Encapsulation is a principle which if sensibly applied brings tremendous 
benefits. But if misapplied it can bring more harm than good. The 
classic example is bank account. Is this version encapsulated?

class bank_account
{
public:
     void set_balance(const money & new_balance);
     money get_balance() const;
private:
     money balance;
};

answer: hardly at all.

Is this one encapsulated?

class bank_account
{
public:
    void deposit(const money & amount);
    void withdraw(const money & amount);
    money get_balance() const;
private:
    ...
};

answer: more than the previous version

I'm saying that, if you think about it real hard it's difficult to come 
up with solid reasons for "encapsulating" access to a lump of const data 
that has no functionality of itself.

> conforms to (an assumed) coding style of functional access to data, 
> and most importantly, is future proof. 

How. Exactly? If the return was by value I could see some mileage in 
what you say. But as a reference return I cannot....

> If at some later date we need decide that in fact the 'SomeData' 
> object is in fact going to reside somewhere else, or any other reason 
> why the member data may change, users of Case 1 don't care - they are 
> unaffected. 

Are they? Suppose the data member changes ; what does the reference 
reference then?

> For no strong reason, case 2 has created a dependency on its internals.

But so has case 1. If you return by reference you have lifetime dependency.

Cheers
Jon






More information about the Effective-cpp mailing list