views:

109

answers:

4

Imagine you have a class with dozens of private member variables. Each member variable has a public getter and a setter function:

class Foo
{
public:
   int GetA() const { return m_a; }
        :
   int GetZ() const { return m_z; }

   void SetA(int val) { m_a = val; }
        :
   void SetZ(int val) { m_z = val; }

private:
   int m_a;
        :
   int m_z
};

Now we have a second class, which is composed of Foo (amongst other things):

class Bar
{
private:
   // some instances of other classes of about the same complexity as Foo
   Foo m_foo;
};

So Bar is essentially a class which binds together instances of other classes in a single entity.

Functions which are passed an instance of Bar will want to access m_foo so that they can call its getter and setter functions. Mindful of Scott Meyers advice in Effective C++ (3rd edition - item #28), I'm reluctant to add something which return a 'handle' to m_foo, e.g.

Foo& GetFoo() const { return m_foo; }   // dubious const, I know

Do I have any other options though other than replicating every single getter and setter in Bar?

I'm working with some legacy code which is lazy enough to make 'm_foo' public! But this goes against some other of Scott's advice (item #22 in this case - "declare data members private").

Any way out of this bind?

+2  A: 

You should make the data member public.

It already is conceptually public, anyway, if you give Bar getters and setters like you describe. This applies similarly to any getter/setter pair where the getter returns a reference. (Except you can include pre/post hooks, but that's a separate issue than encapsulation.)

Roger Pate
Yeesh, folks here are trigger happy with the down vote. There's nothing wrong with making members public, as long as you're aware of what you're doing when you do it. It isn't THAT hard to go back and encapsulate them if it turns out to be necessary.
Daniel Bingham
I would still argue for the getter approach `const Foo` and `Foo`, this way you can instrument the methods (with logs for example) to track down a bug, and it's easier to set breakpoints too... but conceptually, it would be the same.
Matthieu M.
@Matthieu M I would agree with you that that is the overall better method, but I don't think the public member suggestion is so bad it deserves a down vote. Down voting should be reserved for things that are outright wrong, not just that you disagree with - no matter how virulently. There's nothing wrong with public members, they are perfectly legit. They just require some forethought and might lead to a little extra work in the future if certain circumstances arise.
Daniel Bingham
Alcon: I disagree, incidentally. If an answer is "not useful", then it should be downvoted. However, an answer you disagree with can still be useful by coherently presenting an alternate POV that should be considered. As to when things change: planning for the future is hard, and you almost have to make a case-by-case judgement on what you expect will happen. Be careful of violating http://en.wikipedia.org/wiki/YAGNI unnecessarily.
Roger Pate
A: 

If you now anyway have such large classes with getters and setters I don't think its a problem to return the reference to that object, after all there is still a layer in between - you essentially still have control over what is set/get in Foo.

OTOH maybe if you are designing your class to have lots of public properties maybe you should reconsider your design, the more stuff in the class the more unwieldy it is.

EDIT: maybe you could change the data structure of your public members and place them in a map of some sort? that way it would at least save some writing. :-)

get("propertyname")
set("propertyname",value)
Anders K.
A: 

Imagine you have a class with dozens of private member variables. Each member variable has a public getter and a setter function.

Um, I'd rather not. Read here why this is a bad idea.

sbi
Hmmm... interesting article but, no thank you. For several reasons: maintenance, debugging (much easier to set breakpoint in the code than to create conditional breakpoint) and data structure optimization.
BostonLogan
@BostonLogan: I'm not sure I understand. The article argues that a class full of getters/setters isn't a class, it's merely a glorified assembly of getters/setters. It's all about abstraction levels and what OO really is about. This has nothing to do with debugging, and as for maintenance - this has little or no advantage over structured programming.
sbi
Sbi, I would augment author's definition of quasi-classes with "Has no defined Behavior" i.e. does nothing more than simple data structure could do - then yes, it must have public guts. But if object of the class can exhibit behavior and this behavior depends on the state, then state must be private and modifiable by setter only.
BostonLogan
@Sbi addendum: although in the top post it does look like class is simply a struct, so in that case can expose its internals without accessors.
BostonLogan
A: 

Not really, no. You can create forwarding getter and setter for every single getter or setter in foo. You can make the foo instances public or you can create a getter and setter for foo.

Generally I've found, that when facing this sort of situation, it is better to revisit my reasons for encapsulating the data in foo and bar as I have done. Often I will find that it is possible to break foo up into multiple classes and then move the functions that need to access each part of foo's data into the appropriate class as methods. This leads to variables that are actually private member variables of their classes and eliminates the need for setters and getters. This is how object oriented programming is supposed to work.

For a good guide on doing this to legacy code, take a look at Martin Fowler's Refactoring.

Daniel Bingham