Sign in to follow this  

What's the point of private class members and methods(C++)

This topic is 2030 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

When I'm writing classes in C++, I never make anything private. Why?

Because it makes me have to write more code to interface between the public and private parts of the class. This, in turn, increases the time I spend on the project for no gain. I know how the class works and how to use it because I wrote it.

I like to have everything public so that If i'm using the class later, and I need it to do something a little different, It may be possible by tinkering with methods and members that [i]should [/i]be private.


If you are using a class that someone else wrote, I still belive that you would benifit from having everything public. You would still learn how to use the class through the usual means of looking at the documentation, reading tutorials and reading header files. The only difference is that you would have alot more freedom in how you use it.


To be honest, I think I'm missing something big, can someone enlighten me?

Share this post


Link to post
Share on other sites
Freedom also comes with responsibility. When you have direct access to a class' members, you also have to ensure that its invariants are not invalidated. Restricting direct access to members is a way to ensure that its invariants are not invalidate.

If you can only interface with a class through a very limited set of points (its member functions, and not anywhere in the user's code), then you also have a very limited set of places where you have to ensure the class' invariants.

Share this post


Link to post
Share on other sites
One aspect of it of course is being able to make sure your class functions correctly at all times, which comes down to as Brother Bob said making sure your class invariants remain valid at all times. If you are able to formally prove that your class will behave correctly at all times you'll have a much easier time debugging said class, and since a huge amount of development is spent debugging this is a good thing.

When you look at it less formally it pretty much comes down to making sure that you don't do or that someone else using your code doesn't do anything majorly stupid. Try to assume that the people using your code (and yes that includes yourself) have no idea what they're doing. This could well be true if you're working on a large project, and if you have to deal with code you have written a year ago and which you haven't touched since. The chance of touching a function which could possibly mess with the validity of your class will become quite large, with the result that you'll introduce some very nasty and hard to find bugs.

So in the end, use the private modifier where needed, it'll save you from a lot of headaches in the end [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]

Share this post


Link to post
Share on other sites
[quote]To be honest, I think I'm missing something big, can someone enlighten me?[/quote]

Private state encapsulates class invariants.

Here's a good criteria - if I take any public member and modify it, can I leave class in broken/inconsistent/invalid state? If yes, that's variable is class invariant and it must be hidden away as public.

[code]struct String {
char * data;
size_t length;
}

String s;
...
s.length = 2000; // oops, we say we have 2000 characters, but data was only allocated for 60[/code]

Another example:[code]struct Person {
std::string name;
std::string address;
}

Person p;
p.name =""; // fine
p.name = "akstgh;a jfdgh;siodhfg; oainhrg; oa he;orgha n;odih a;oiga ;oi"; //fine
p.address = "42 Wallaby Way"; // fine[/code]Nothing I can do in this case can break the class. All values are valid, all class invariants are enforced by string itself. Some values might not make sense, but that's for rest of application to enforce.


Another good criteria is this:
If I take any public member and assign it completely random value, will the class break? Then it cannot be public.

Share this post


Link to post
Share on other sites
Systems with everything being public will most likely turn into an unmaintainable mess.
Exposed implementation details mean you can't change them without affecting lots of dependent stuff.
Having a huge public interface introduces a massive amount of coupling, side effects and resulting efforts to maintain them.
Lean interfaces mean less possible points to break things.
Well thought interfaces are also implicit documention (and forces you to [i]think [/i]and rethink about requirements and finding optimal solutions instead of just typing p-u-b-l-i-c and going on)

All in all, this is one of the biggest no-nos you can think of.
Writing software is just too complex - you have to introduce shields and safety guards. Edited by 6510

Share this post


Link to post
Share on other sites
[quote name='Antheus' timestamp='1336913097' post='4939765']
Another good criteria is this:
If I take any public member and assign it completely random value, will the class break? Then it cannot be public.
[/quote]
Yeah, but perhaps phrase that as "If I take any public member and assign it completely [i]arbitrary[/i] value, will the class break?"

Another reason could be that you don't want the user to be taking the address of a member for whatever reason, so your getter function will only return a by-value copy

Share this post


Link to post
Share on other sites
[quote name='Lith' timestamp='1336909268' post='4939754']
I know how the class works and how to use it because I wrote it.
[/quote]

That's going to change when your code starts getting to tens of thousands of lines. I have code that I wrote years ago and haven't touched since. I can't remember how it works and even if I scan the code and start to remember the general flow, there is no way I can remember all of the intricacies.

Making everything public means that anyone using that code (including you) has to know exactly how it works and exactly what changing any variable would do. You can get away with making everything public for a tech demo or proof of concept, because they are programs which will get coded and never touched again. But for anything else, "an ounce of prevention is worth a pound of cure" Edited by turch

Share this post


Link to post
Share on other sites
I had the same initial reaction to using private when I first heard about it, maybe 20 years ago. During this time I have learned that there is real value making the public interface be what you want anyone to be able to do with your class, while details of how those things are achieved can be kept private and changed at any time, without having to worry about breaking the caller's code.

Another type of seemingly artificial constraint that is really useful is `const'. Just as it is with `private', if you use it correctly the compiler will stop you from accidentally doing things that you are not supposed to be doing, and you will have many fewer bugs in your code. Edited by alvaro

Share this post


Link to post
Share on other sites
At the end of the day even if you encapsulate something someone can still get in there and change its value if they really want to through some terribly hacky techniques. You can't stop THAT level of stupidity but what you can do is hinder most people doing most stupid things and that's a good thing.

I don't know where I am on this topic yet really. I have seen a lot of cases in the games industry where 'solid' OO practices such as inheritance, encapsulation, overloading, overriding, templates and so on hinder productivity through over engineering and that is a bad thing. Although there is some sound advice in this thread it would be good for you to find out through attempting to use your own codebase as it grows larger and larger and learn your lessons that way. I can't tell you how many iterations of coding style and approach i have been through while feeling out what I personally think is the best way.

Your opinion will no doubt change as you become more experienced.

Share this post


Link to post
Share on other sites
One advanced and very important concept that you may come across in the foreseeable future, is the idea of the [b]separation[/b] of a class's [b]interface [/b]with its [b]implementation[/b]. Such concepts are extremely powerful, allowing class implementers to change their classes at will, so long as the original interface doesn't change. Such concepts are used regularly, for example in patching up and updating software via the internet, something that virtually all of us have done at one time or another. So, regardless of your particular points of view on this topic, you too have been benefiting from these ideas!

Indeed there are languages around, such as the Interface Definition Language (IDL), whose sole purpose is to define interfaces only, allowing class implementations to remain private and totally encapsulated. Some implementations will even be beyond [b]any[/b] means to hack, as outlined by Dave above, because with this ability of being able to separate interface from implementation, the implementation doesn't even need to be on the host machine!

Anyway, I digress. All I am saying is, don't take this concept too lightly. I too believe that, with time, your opinion will change. Encapsulating software is one of the most fundamental concepts to have emerged over the past few decades. Indeed, perhaps such a powerful concept was one of the reasons why Bjarne Stroustrup developed C++ in the first place!

Share this post


Link to post
Share on other sites
[quote name='Lith' timestamp='1336909268' post='4939754']
Because it makes me have to write more code to interface between the public and private parts of the class. This, in turn, increases the time I spend on the project for no gain. I know how the class works and how to use it because I wrote it.
[/quote]

If you're talking about the need to make Get/Set functions for every single data member, then I'd agree that this is only marginally better encapsulated than just making that data public. It does have some advantages: at least those accessors can maintain/check your class invariants. But still, it's kind of missing the point. As a general rule, if you find yourself wanting accessors all over the place, your class is poorly thought out and would probably benefit from a rethink.

Share this post


Link to post
Share on other sites
[quote name='Sandman' timestamp='1337100228' post='4940457']
If you're talking about the need to make Get/Set functions for every single data member
[/quote]
This is where templates can come in play. It's not hard to overload operator= to set/get values, if you need something custom just pass lambda or make specialized template and you're all set. Compiler should inline everything, making interface look all public while it's actually all private except methods.

Can't seem find original article, but this should give general idea:
[CODE]
template<typename T, T DefaultValue>
struct PropertyBasic {
private:
T value;
public:
PropertyBasic() : value(DefaultValue) { }
operator T () { return value; }
T operator=(const T &newValue) { return value = newValue; }
};

template<typename T, T DefaultValue, typename Setter>
struct PropertySetter {
private:
T value;
public:
PropertySetter() {
Setter::set(value, DefaultValue);
}
operator T () { return value; }
T operator=(const T &newValue) {
return Setter::set(value, newValue);
}
};

struct MyClass {
struct mysetter {
static int set(int &value, int newValue) { return value = newValue * 2; }
};
PropertyBasic<int, 10> Health;
PropertySetter<int, 10, mysetter> VariableWhichDoublesSetValue;
};

void main() {
MyClass foo;

foo.Health = 100;
cout << foo.Health << endl; // 100

foo.VariableWhichDoublesSetValue = 99;
cout << foo.VariableWhichDoublesSetValue << endl; // 198
}
[/CODE]

P.S. Ignore bad style and stuff. Edited by Ripiz

Share this post


Link to post
Share on other sites
[quote name='Ripiz' timestamp='1337111470' post='4940502']
[quote name='Sandman' timestamp='1337100228' post='4940457']
If you're talking about the need to make Get/Set functions for every single data member
[/quote]
This is where templates can come in play. It's not hard to overload operator= to set/get values, if you need something custom just pass lambda or make specialized template and you're all set. Compiler should inline everything, making interface look all public while it's actually all private except methods.
[/quote]

Finding cleverer ways of implementing accessors like this might be neat from a language point of view, but it's still kind of missing the point. *Not to mention the fact that overloading operators in non-standard ways can make your code incredibly difficult to follow, and is something that should be done only with great caution. If I see functions called 'SetFoo(int)' and 'SetBar(float)' I have a vague idea what they do: with an overloaded operator = I get nothing.

The key point is that a well encapsulated class is not a great big blob of data to be poked around in by anyone who cares to look, it's an [i]implementation [/i]of some piece of functionality - and the details of how that implementation works (and the data it needs to get there) should not be exposed outside of that class, except where absolutely necessary. The main thing I'm trying to get across is that having access to all of a class's private members not only annoying to write, but it's still poor encapsulation, and in the vast, vast majority of cases, completely unnecessary.

*edit: ah ok I see your edit now, so the warning about operator overloading isn't really relevant. Still, the point about accessors being largely unnecessary holds.

Share this post


Link to post
Share on other sites
When it comes to making things private I like to think of it like this; the person who is going to maintain and work with this code is an idiot who hates you aka yourself in 6 months when you've forgotten WHY you done things.

I mostly base this on my tendency to come back to code I've written on a friday on a monday morning and spend the first 20mins trying to work out just how high I was at the time of writing it :D

Share this post


Link to post
Share on other sites
[quote name='Ripiz' timestamp='1337111470' post='4940502']
Can't seem find original article, but this should give general idea:
[/quote]

Personally I prefer to avoid the setter part and stick with
property() //getter
property(value) //setter

Ie. overload operator() for both instead of using = for the setter

The idea is that all "default" stuff can be handled with a property template and when you actually do need special get/set behaviour you go back to a private variable with appropriately named get/set function. To the outside it will look exactly the same, be a familiar style (QT and parts of the C++SL use it as well) and it won't give the illusion of directly accessing a variable (which I feel = does).

Share this post


Link to post
Share on other sites
[quote name='Trienco' timestamp='1337142313' post='4940579']
Personally I prefer to avoid the setter part and stick with
property() //getter
property(value) //setter
[/quote]

That could work as well. However, I prefer [i]player.position = player.position + player.velocity;[/i] instead of [i]player.position(player.position() + players.velocity());[/i].
First way makes more sense to me, but it's just matter of perspective I guess.

Share this post


Link to post
Share on other sites
[quote name='Antheus' timestamp='1336913097' post='4939765']
Private state encapsulates class invariants.
[/quote]

And as we know, enforcing invariants is the only valid reason to create a class. (to paraphrase [url="http://www.artima.com/intv/goldilocks3.html"]Stroustrup[/url])

Rather than asking "what are private members for?", better to ask "what are public members for?" and "why am I creating these class things anyway?" Edited by mrbastard

Share this post


Link to post
Share on other sites
[quote name='Ripiz' timestamp='1337149405' post='4940600']
That could work as well. However, I prefer [i]player.position = player.position + player.velocity;[/i] instead of [i]player.position(player.position() + players.velocity());[/i].
First way makes more sense to me, but it's just matter of perspective I guess.
[/quote]

I prefer player.update(delta) personally. The specifics of what that does is up to the player, not calling code.

Share this post


Link to post
Share on other sites
[quote name='Lith' timestamp='1336909268' post='4939754']
I know how the class works and how to use it because I wrote it.
[/quote]

correct this to

[quote name='Lith' timestamp='1336909268' post='4939754']
I [i][b]NEED TO [/b][/i]know how the class works and how to use it [i][b]ALL THE TIME [/b][/i]because I wrote it.
[/quote]

if you properly hide the stuff you don't need from the outside, you don't NEED TO know how the class works anymore. you can then use your mind for more important stuff: the NEXT thing you do.

Share this post


Link to post
Share on other sites

This topic is 2030 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this