When are public variables in a class OK?

Started by
21 comments, last by dalep 18 years, 5 months ago
Hi, I am pretty new to c++ but I am learning it because I have to for uni. Anyway I am starting to get the hang of it but I have got a bit confused making my animation class's. Then I looked at the cone3D tutorial to see how he did it and I noticed to get variables between some of the class's he just made them public. Now until now I have be told by everyone to make all variables in a class private except very occasionaly, so I was wondering when you would use public variables? Normaly I could just make a get_bob() function to get the value of bob instead of making it public but when I have to get the value of a variable through two class's it gets a bit harder! Anyway thanks, David
Advertisement
Make a variable public when the point of the variable in the class is just to have somewhere to store the data and make it accessible to anyone and everyone. However, in most cases that's not the purpose of a variable in a class.
If you need to use 2 classes to get a value your design is likely bad.
If you decide to keep it, a better way than public variables is declaring the classes as friends.
If the variable can be changed to any value at any time without affecting anything else, and it is information that the world at large needs access to, then making it a public variable is fine.

If you have a simple 3d vector, for instance, making the x, y, and z variables public is probably OK.

If you have a normalized 3d vector, though, they shouldn't be public. x, y, and z can not take on any random values, they can only take on points on the unit sphere.

CM
Quote:
Normaly I could just make a get_bob() function to get the value of bob instead of making it public but when I have to get the value of a variable through two class's it gets a bit harder!

How do you mean?

If ClassA contains an object ClassB, and ClassB contains an integer SomeValue, you could do this (providng you had the relevant get / set routines):

instanceOfClassA.getInstanceOfClassB().getSomeValue();

Although, IMO, get/set routines should only be used when they perform some validation or other operation on the data member being returned. If they contain nothing more than a return statement, it usually isn't worth it.
C++ advocates will tell you to always make all variables private. But essentially it's only a protection to prevent the programmer from writing 'spaghetti code'. It's perfectly possible to have good code without any private variables, it's just harder (pure C code).

The most important thing is to encapsulate your implementations and only allow access through interfaces. If the code behind that interface uses public variables, but works fine, then that's not too bad. So it's important to see the distinction between implementation and interface. Many classes have both an interface part (public methods), and implementation part (functions and data, highly recommended to keep private). Other classes are purely interfaces (all virtual methods, no variables). And finally there are classes which are purely implementations (representing an algorithm).

So when exactly is it ok to have a public variable? Well, the rule of thumb is to always make every variable private, unless it's very cumbersome to use access methods and you're absolutely sure no encapsulation is needed now or in the future. One perfect example is a vector class with x, y, z variables. It's pretty useless to make these private (exceptions exist but are extremely rare).
If the members being physically stored are essential to the concept, such as with ::std::pair instantiations, then it's usually okay to have the members be public. Such as with pairs, the whole point is just grouping together values of any type, providing full access to both, so making them public is generally fine. Even still, there are some times where it's beneficial to return a non-const reference to a private datamember from a member function, even if the member in question should be able to be accessed completely, such as when you need the same pure abstraction for working with both values and proxies.

A good example of this which I'm dealing with now is a library I'm developing for reprenting quantities with attached units. Often times, other libraries, such as graphics libraries, use raw values/arrays/other types to represent points and vectors in space, without explicitly attaching length units. Because of this, such data has to be stored in a raw form, however, it's nice to adapt iterators to such types or directly create proxies to individual elements which provide the added level of abstraction of attaching units and providing appropriate operator overloads, member functions, type/template members, etc.

Such proxies should have the same interface as quantities which directly contain their values so that they can all be used in expressions while using the same syntax. The fact that some are proxies and some are the actual types should be an implementation detail. Since the proxies can't contain the datamembers directly, a function returning a reference is the only option. Rather than having two different interfaces for the same concept, which would cause the problems above, the pure abstraction just involves a function returning a reference rather than having a public datamember. For the non-proxy, the datamember could still be public as well, but that would just be creating a redundant way to access the same data, so it's better not to.

So I guess the rule I'd say is, always prefer private members where you can, use public members if the concept of the encapsulating type requires that the type contains the data directly (which in-and-of-itself is an extremely rare occurrence), unless you need a more general abstraction with proxies or other similar high-level concepts, in which case a function returning a reference may be the better approach.
me, MaulingMonkey and a bunch of other people recently had a discussion about this here which might be of interrest. Most people prefer using private data and accessor functions, but MaulingMonkey raised some interresting points for the contrary.
Variables should be public when they are part of the interface and changing their value can't affect the validity of the object. In this case, accessors would only add unnecessary complexity to the interface.

For example, the x, y, and z components of a generic 3D vector should be public, while the x, y, and z components of a normal should not (because it must always have a length of 1).
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
I use public variables if retrieving them is a speed concern.

This topic is closed to new replies.

Advertisement