Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


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


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
19 replies to this topic

#1 Lith   Members   -  Reputation: 398

Like
0Likes
Like

Posted 13 May 2012 - 05:41 AM

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 should 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?

Sponsor:

#2 Brother Bob   Moderators   -  Reputation: 8566

Like
1Likes
Like

Posted 13 May 2012 - 05:59 AM

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.

#3 Radikalizm   Crossbones+   -  Reputation: 2973

Like
0Likes
Like

Posted 13 May 2012 - 06:27 AM

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 Posted Image

I gets all your texture budgets!


#4 Antheus   Members   -  Reputation: 2397

Like
0Likes
Like

Posted 13 May 2012 - 06:44 AM

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


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.

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

Another example:
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
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.

#5 6510   Members   -  Reputation: 151

Like
0Likes
Like

Posted 13 May 2012 - 06:48 AM

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 think 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, 13 May 2012 - 06:50 AM.


#6 hupsilardee   Members   -  Reputation: 487

Like
0Likes
Like

Posted 13 May 2012 - 06:49 AM

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.

Yeah, but perhaps phrase that as "If I take any public member and assign it completely arbitrary 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

#7 Waterlimon   Crossbones+   -  Reputation: 2633

Like
0Likes
Like

Posted 13 May 2012 - 07:40 AM

You might also want to later add code to the getters and setters to check for the validity of the value or something like that if its a more complex class.

o3o


#8 turch   Members   -  Reputation: 590

Like
0Likes
Like

Posted 14 May 2012 - 07:37 AM

I know how the class works and how to use it because I wrote it.


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, 14 May 2012 - 07:38 AM.


#9 Álvaro   Crossbones+   -  Reputation: 13880

Like
0Likes
Like

Posted 14 May 2012 - 08:28 AM

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, 14 May 2012 - 08:28 AM.


#10 Dave   Members   -  Reputation: 1526

Like
0Likes
Like

Posted 14 May 2012 - 09:06 AM

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.

#11 CodeStorm   Members   -  Reputation: 127

Like
0Likes
Like

Posted 15 May 2012 - 09:29 AM

One advanced and very important concept that you may come across in the foreseeable future, is the idea of the separation of a class's interface with its implementation. 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 any 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!

#12 Sandman   Moderators   -  Reputation: 2136

Like
1Likes
Like

Posted 15 May 2012 - 10:43 AM

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.


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.

#13 Ripiz   Members   -  Reputation: 529

Like
0Likes
Like

Posted 15 May 2012 - 01:51 PM

If you're talking about the need to make Get/Set functions for every single data member

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:
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
}

P.S. Ignore bad style and stuff.

Edited by Ripiz, 15 May 2012 - 02:20 PM.


#14 Sandman   Moderators   -  Reputation: 2136

Like
0Likes
Like

Posted 15 May 2012 - 02:19 PM


If you're talking about the need to make Get/Set functions for every single data member

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.


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 implementation 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.

#15 phantom   Moderators   -  Reputation: 7553

Like
0Likes
Like

Posted 15 May 2012 - 03:13 PM

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

#16 Trienco   Crossbones+   -  Reputation: 2223

Like
0Likes
Like

Posted 15 May 2012 - 10:25 PM

Can't seem find original article, but this should give general idea:


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).
f@dzhttp://festini.device-zero.de

#17 Ripiz   Members   -  Reputation: 529

Like
0Likes
Like

Posted 16 May 2012 - 12:23 AM

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


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

#18 mrbastard   Members   -  Reputation: 1573

Like
1Likes
Like

Posted 16 May 2012 - 02:23 AM

Private state encapsulates class invariants.


And as we know, enforcing invariants is the only valid reason to create a class. (to paraphrase Stroustrup)

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, 16 May 2012 - 02:24 AM.



#19 Aardvajk   Crossbones+   -  Reputation: 6179

Like
1Likes
Like

Posted 17 May 2012 - 04:15 PM

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


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

#20 davepermen   Members   -  Reputation: 1021

Like
0Likes
Like

Posted 25 May 2012 - 07:09 AM

I know how the class works and how to use it because I wrote it.


correct this to

I NEED TO know how the class works and how to use it ALL THE TIME because I wrote it.


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.
If that's not the help you're after then you're going to have to explain the problem better than what you have. - joanusdmentia

My Page davepermen.net | My Music on Bandcamp and on Soundcloud





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS