tags:

views:

292

answers:

5

Is it ok to have public data members in a C++ class/struct in certain particular situations? How would that go along with inheritance? I've read opinions on the matter, some stated already here

http://stackoverflow.com/questions/952907/practices-on-when-to-implement-accessors-on-private-member-variables-rather-than http://stackoverflow.com/questions/670958/accessors-vs-public-members

or in books/articles (Stroustrup, Meyers) but I'm still a little bit in the shade.

I have some configuration blocks that I read from a file (integers, bools, floats) and I need to place them into a structure for later use. I don't want to expose these externally just use them inside another class (I actually do want to pass these config parameters to another class but don't want to expose them through a public API).

The fact is that I have many such config parameters (15 or so) and writing getters and setters seems an unnecessary overhead. Also I have more than one configuration block and these are sharing some of the parameters. Making a struct with all the data members public and then subclassing does not feel right. What's the best way to tackle that situation? Does making a big struct to cover all parameters provide an acceptable compromise (I would have to leave some of these set to their default values for blocks that do not use them)?

A: 

It sounds like you just need to make these members protected - that way they can be accessed by derived classes but are not public.

Paul R
`protected` fields are (almost?) as bad as `public` fields.
Konrad Rudolph
+1  A: 

If the class you want accessing the internals inherits from your main class, setting things protected will do what you like. If you want another unrelated class to have access you have to make them friends.

JUST MY correct OPINION
`protected` fields are (almost?) as bad as `public` fields.
Konrad Rudolph
I'm not recommending the practice. Just telling the OP how to get done what he says he wants to get done.`friend`ing is even worse, IMO. ;)
JUST MY correct OPINION
No, that’s a misconception. Usage of `friend` is completely fine, since it doesn’t violate encapsulation, as opposed to `protected` and `public`. With `friend`, you as the writer of the class exclusively control who gets access to the internals. With `protected`, you completely give that control up.
Konrad Rudolph
OK, fair enough. On the other hand friends can fondle your privates. It seems friendship is very libertine in C++. I'd prefer a bit finer-grained control than all-or-nothing.
JUST MY correct OPINION
+3  A: 

If you have a data structure that isn't intended to have behaviour but genuinely is nothing more than a pure struct in the C sense, particularly if each instance of it is only used internally to the implementation of other "proper" classes, then it is fine to make it a struct and have public fields. After all, as you've pointed out, once you've given it get/set accessor functions for every field then you're back to the logical equivalent of public data anyway.

Daniel Earwicker
That's what I thought in the first place but then ... how would I handle the difference between configuration blocks? Through inheritance or just make another plain struct? The blocks do share some data.
celavek
A struct can have another struct as a member, so you can "include" them inside one another in that way. This has the advantage (over inheritance) that you won't ever get name clashes.
Daniel Earwicker
Daniel, I disagree (and so does Scott Meyers, if that has more weight). There’s a long shot between public fields and public accessors when it comes to encapsulation. In particular, the latter are future-proof and changing the internal logic will (probably) not mangle the interface, nor introduce binary incompatibility. Changing fields, on the other hand, *always* will.
Konrad Rudolph
@Konrad, you may have missed "if each instance of it is only used internally to the implementation of other "proper" classes". It's quite common for the internals of some well-defined class to make use of a struct, e.g. a COW string class might internally use a struct for the shared data. Clients of the class have no idea this is happening, so it's fine. As for binary compatibility, I can't see much point using C++ at all across that boundary, except in some carefully limited form, due to name mangling (merely changing compiler versions would potentially break binary compatibility).
Daniel Earwicker
@Daniel: yes, I missed that. As for binary compatibility, that’s mainly useful because you don’t need to recompile object files unnecessarily. In large projects, this may be a *huge* factor to consider, since C++ compiles so **darn** slowly.
Konrad Rudolph
+2  A: 

I usually write my program config files using Google's protocol buffers. The getters and setters (among many other useful functions) are generated for you, similar to a struct. It also makes editing your config files trivial, allowing for obvious field naming and grouping.

http://code.google.com/apis/protocolbuffers/

Stephen
Wouldn't fit my situation but an interesting link nevertheless.
celavek
A: 

The fact is that I have many such config parameters (15 or so) and writing getters and setters seems an unnecessary overhead.

This can be solved elegantly by a macro. This is the solution I’d recommend.

Proof of concept:

#define MAKE_ACCESSOR(type, name) \
    private: \
        type _##name; \
    public: \
        type const& name() const { return _##name; } \
        void name(type const& new_value) { _##name = new_value; }

…

class foo {
    MAKE_ACCESSOR(int, x)
    MAKE_ACCESSOR(int, y)
};

#undef MAKE_ACCESSOR
Konrad Rudolph
I wasn't referring to the actual writing of the code. I prefer writing the code myself than hiding under such preprocessor magic ... but that's just me I guess
celavek
@Marius: if not to the writing, then to *what*? And there’s no magic going on here. Such code generation is the prime use case of macros.
Konrad Rudolph
Huh. Why the downvote?
Konrad Rudolph
I wonder also why the downvote. Maybe downvoters should be forced to add a comment.
celavek
@Marius this has been suggested countless times but Jeff seems unwilling …
Konrad Rudolph