Non private privacy

Started by
68 comments, last by Emmanuel Deloget 17 years, 10 months ago
This is probably a really bad question, but I occasionally have parts of code that look exactly like this. And every time I write it, I'm wondering why I bother.
class Car
{
private:
   int Color;
public:
   const int GetColor() const { return Color; }
   void SetColor(int c) { Color = c; }
};
Would it not be easier to just
class Car
{
private:
...
public:
  int Color;
}
I know some members need an interface for validation, or conversions, or may not even need to be writable at all. But is that why I pretend to make things like this Color variable private, even though it really isn't? To be consistent? So that I don't have 10 private member variables and 4 public? Even though the ton of pointless interface functions makes my class even harder to write, manage, and understand?
Advertisement
To my opinion, the top code is a waste of time. But I would like it if member variables could have a public read and a private write.
---------------------------------Upon thine ass shall I bust but a single cap.
From now on I make variables with both a get() and a set() public. I had code that looked like (before, that is):
ship.setx(ship.getx() + ship.getxspeed());if (ship.getx() > SCREEN_W)    ship.setxspeed(ship.getxspeed() * -1);

Now it's:
ship.x += ship.xvel;if (ship.x > SCREEN_W)    ship.xvel *= -1;

Note how if you make it public you can make use of operators such as += and *=, which is impossible with gets and sets.
Quote:Original post by agi_shi
Note how if you make it public you can make use of operators such as += and *=, which is impossible with gets and sets.


You can use the += and *= operators with getters and setters if you pass by reference, but that kind of kills the purpose of making the variable private. Sometimes it makes sense though, especially when getters and setters have more code then just return and set.

#include <iostream>using namespace std;class Int{	int i;public:	void set(int l){i = l;}	int& get(){return i;}};int main(){	 Int i;	 i.set(1);	 i.get() += 1;	 cout << i.get() << endl;}
deathkrushPS3/Xbox360 Graphics Programmer, Mass Media.Completed Projects: Stuntman Ignition (PS3), Saints Row 2 (PS3), Darksiders(PS3, 360)
Quote:Original post by F-Kop
But I would like it if member variables could have a public read and a private write.

You can accomplish this if you pass structured objects as a const reference.
const CarData &data = Car.GetData();
int test = data.WheelSize; // this is okay
data.WheelSize = 1; // this isn't
the whole point of making data private is encapsulation.

So if something is buggy, and you know it is to do with a certain variable, then the problem must be somewhere inside that class, or through its public interface.

I make extensive use of the const keyword in my engine to manage what kind of access each component has to other components.

Eg.

class Foo
{
private:
int bar;
public:
bool SetBar( int );
int ReadBar( void ) const;
int& AccessBar( );
}

if you only have const access to the class (Eg. const Foo& = GetFoo() ) then you can only call ReadBar to copy the value, but if you have full access you can use SetBar or get full access to the actual variable by:
int& bar = myFoo.AccessBar();
bar += 10;
etc...


When i started off writing C++ I never used private, as I thought it was a waste of time. Everything was public, and maintanence was a nightmare.

Now that im writing professional game engine I cant live without the private and const keywords.

I really reccomend you read "Effective C++ 3rd edition" if you want to be a pro C++ coder. I thought I was 'good' at C++ untill I read this, but it explains the reasons why you should do lots of things (like using private).
Quote:

So if something is buggy, and you know it is to do with a certain variable, then the problem must be somewhere inside that class, or through its public interface.

This only applies if there are constraints on the variable, e.g. the valid values for it are restricted even more than the type of the variable. If the variable is just an integer and any value is valid, this doesn't matter anymore since it can never become "buggy."

The reason to wrap variables (which don't even have to be private) with get/set functions is usually either to 1) enforce constraints on the variable or 2) allow for possible change, e.g. if you decide to remove the variable all together and instead retreave it dynamically from a file. The first is simply a biproduct of C++'s rather featureless type system, so you're generally forced to use it if you want to maintain an invariant. The latter really depends on your situation and how likely it is that you'll need to change it. If it will never change, or change is very unlikely, making them public is fine--after all, when was the last time you decided to retreave the x and y values of a rectangle from a file or over a network every time you access it ;)
I have a class X and a class Y
class X{public:   int m_someVar;};class Y{public:   int GetAVar() const { return m_someVar; }   void SetAVar(int someVar) { m_someVar = someVar; }};


These classes are used commonly throughout my code. Later on, I decide I want to log every time the value of m_someVar changes, or I decide that I'd like to do a lazy evaluation on m_someVar. For clients of class Y, I just change the implementation of GetAVar and SetAVar and recompile. Clients of X are stuffed.

Read Scott Meyers "More Effective C++" (Item: program in the future tense). Write your code so that it can be extended.
if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight
Quote:Original post by agi_shi
From now on I make variables with both a get() and a set() public. I had code that looked like (before, that is):
*** Source Snippet Removed ***
Now it's:
*** Source Snippet Removed ***
Note how if you make it public you can make use of operators such as += and *=, which is impossible with gets and sets.


That's an improvement, but it *should* be more like:

void Ship::move(int left, int right) {  x += xvel;  if (x < left || x > right) { xvel *= -1; }  // FIXME: also clip the position. Possibly cut the motion for the 'critical'  // frame into the normal part and reflected part, and work out a more  // accurate position?}ship.move(0, SCREEN_W);
One of the reasons to use Sets and Gets also is to make sure the data is valid. Say you are doing some graphic's work. You have a Class for Pixil. In this class you have an X and a Y members. In your set you make sure that the X and Y are within the bounds of the screen. Now being extra paranoid when you do a get you test to make sure the value is within the bounds, if not you toss an assert. This protects your data at all times. Anyone that is using your class will know that it will always give valid data and will give errors when you try to use it wrong. This is writing roboast code. If more people would do this there would be a lot fewer bugs in programs.

theTroll

This topic is closed to new replies.

Advertisement