-
Classes - Confusion
hi
i was just readin the article:
http://www.cprogramming.com/tutorial/lesson12.html
but something i dont understand about classes is,
why set the data members private and then use set and get functions to read/set these variables?
why not just set them public?
surely it would save on writing alot of code?
im so confused :p
Kane
-
Sometimes it's very handy to have data members that the outside world cannot get to. It helps to ensure the integrity of the data that your class is using. For instance, what if you wanted a read-only variable? This variable could be a private member set on construction, and then only accessed with a Get accessor.
Code:
class A
{
public:
A(int a) : m_a(a) {}
int GetInt() {return m_a;}
private:
int m_a;
}
Now any instance of that class will have a data member that cannot be changed after construction.
-
ah right, that makes sense. thanks
but that doesnt explain why you would create a set function :p
because surely if you also created a set function ...you might as well have set the variable (int m_a) to be public?
-
Also another big reason is range checking.
Lets say you are doing a grade book type of class. Inside you want to store their grades. Lets say they can score between 0 and 100 inclusive. So your class my look like:
Code:
class Grades
{
int score;
/* other stuff */
public:
int GetScore() const { return score; }
void SetScore(int s) {
if ( s < 0 )
score = 0;
else if (s > 100 )
score = 100;
else
score = s;
}
};
Now they can only set a score between 0 and 100. If you had it public they could assign any value they wanted which could screw up your calculations.
-
thanks alot guys
it makes much more sense to me now :D
Kane
-
Additionally...take a Date/time class as an example...
The set and get functions can ensure legal ranges/dates (as mentioned above), as well as can be setup to receive dates and times in numerous formats, parse out the user input into it's pertinent pieces of data (ie. Day, month, year, hour, minute and second) and set the appropriate variables. So logically, a user can input Jan 31, 1995 / Noon and your class can be intelligent enough to set Month to 1, Day to 31, Year to 1995, Hour to 12, Minute to 0, and Second to 0.
And as was mentioned previously, it enables error checking (ie, ensures you can't sed Feb 29th in a non leap-year).
-
One more advantage is that it abstracts away the storage of the data. For example, let's suppose you're implementing the edit control of a cross-platform GUI library. Among many other things, you have a background colour for the control.
How do you get and set it? In the Win32 implementation, you'd have a color member and use it to intercept and handle WM_CTLCOLOREDIT. (If there is such a thing...) The Win32 edit control doesn't store its own colour, it requires the user to set it every time the edit needs to redraw itself.
So, you'd have the interface like this:
Code:
class Edit {
public:
colortype color;
};
And then people can set this color member and the color changes.
Well, first case for the setter is that it doesn't change. The color won't change until a redraw, which means that the user would still have to call Redraw(). But with a setter, you can do that yourself:
Code:
class Edit {
colortype color_;
public:
colortype getColor() { return color_; }
void setColor(colortype color) { color_ = color; redraw(); }
};
Then you're porting the whole thing to, say, Gnome and want to use GTK widgets. Now, a GTK edit control, if I recall correctly, does store its own color information, so suddenly your member becomes redundant.
What you can do then is to change the privates:
Code:
class Edit {
gtk_widget *widget_;
public:
colortype getColor() { return gtk_get_color(widget_); }
void setColor(colortype color) { gtk_set_color(widget_, color); }
};
Just one of many advantages.
-
I stole an example from you CornedBee :(
Code:
class Edit {
colortype color_;
public:
colortype getColor() { return color_; }
void setColor(colortype color) { color_ = color; redraw(); }
};
One of these days, you might go back to this and someone enters a color type of colortype.NOCOLOR, and for some reason you don't want that happening, so now since you already have the modifier functions, you can do this:
Code:
class Edit {
colortype color_;
public:
colortype getColor() { return color_; }
void setColor(colortype color)
{
if(color != color.NOCOLOR)
color_ = color; redraw();
}
};
If you didn't have the modifier functions, then you would have to rewrite A LOT of code that used class Edit to edit public color_ directly to a modifier function that checked for color.NOCOLOR
-
In short, accessor functions give you the ability to perform additional actions on setting and getting values, completely transparent to the user.