• Advertisement
Sign in to follow this  

Why not make everything public in a class?

This topic is 4762 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

Advertisement
Consider a string class which does keep track of its length. You want that length to be modified by operations that affect the contents of the string, but you don't want people to arbitrarily modify that field, possibly to invalid values, making it inconsistent with the actual text the string contains.

Some other times, you will have broken down a class operation into multiple, elementary functions. You probably don't want people to call those functions (they might need to be called in a specific order, under specific conditions...), but only those which are properly part of the class interface.


Making things private is thus a way to protect your class invariant, as well as hiding implementation details by forcing people to use a specified interface (Encapsulation).

If your class is just a data holder with no invariant to preserve, making everything public is perfectly fine. Protected really means "public to derived classes", so the principles above still hold, just for a different audience.

Share this post


Link to post
Share on other sites
Sometimes you aren't the only person that modifies code that you have written. If that was the case then perhaps it wouldn't matter. But one reason I can think to make it private is to ensure your data is only accessed through a set method that you write therefore prohibiting that variable from being assigned certain values. Let's say you have a class:

class Student{

private age;

public setAge(int a){
if(a<0)
age = 1;
else
age = a;
}
}

Now without the private accessibility anyone reusing your code could simply make an object of the student class:

Student stud = new Student();

and then set age like:

stud.age = -5; //wrong!

Since age is private he is forced to modify it with the public setAge method ensuring it is never negative.

stud.setAge(-5); //age variable set to 0

That's one example I can think of. I am sure there is a lot of technical jargon that could better explain good software design principles but that's how I understand it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Meta Adam
The name says it all..
Why make something private or protected in a class?


Another way to think about is if you make an analogy between a class and your life - would you really want everything public for your parents as well as others [smile]. With that said I agree with HughG and Fruny. Moreso with silly analogy's, since im on a roll [lol], think about all your money as being a class - would you let everyone know how much you had and that they could use it however they like?

Just a few examples. I hope it helps!

- Drew

Share this post


Link to post
Share on other sites
Thanks for your replies. =)
Is this the right way to use it though?

class dog {
private:
int age, height, weight;
public:
int set_age(int) {
int dogage = age;
};
void bark() {
cout<<"Bark bark"<<endl;
};
int set_height(int) {
int dogheight = height;
};
int set_weight(int) {
int dogweight = weight;
};
dog();
~dog();
}


p.s. I forgot how to post code the right way.. what are the tags for it?

[Edited by - Meta Adam on January 3, 2005 9:23:11 PM]

Share this post


Link to post
Share on other sites
Those set/get functions are commonly referred to as setters/getters. In your example it doesn't make much sense to return anying but void (unless you're doing error checking, in which case you may want to return a 1 if the set was succesful and a 0 otherwise.) The thing about setters/getters to watch out for is making sure they don't unnecessarily overcomplicate your code. Fruny's example is a good case where using setter/getter functions would be a good idea, because you don't want someone changing the string without the size variable changing as well (afterall, this may break code). Just keep that in mind when designing classes and you'll be fine. The string class is really good candidate for operating overloading, because you'll be able to use normal symbols (+, =, ==, etc), but they'll actually be calling an overloaded function which can do anything you want them to do.

Share this post


Link to post
Share on other sites
Yea, but i dont understand why it couldnt just be:

#include <iostream>
using namespace std;
class dog {
public:
int age;
int weight;
int height;
void bark();
{cout<<"bark bark."<<endl;}
}
int main() {
dog fido;
fido.age = 4;
fido.weight = 5;
fido.height = 14;
cout<<fido.age<<fido.weight<<fido.height<<endl;
bark();
return 0; }

Share this post


Link to post
Share on other sites
generally I don't bother with get/set. A single overloaded access function for each property is enough:
int age();
void age(int);
Also since the majority of my classes seem to be public access, & I always inherit public - I use structs instead of classes.
Only difference with structs is that they are public by default (whereas classes are private)

Share this post


Link to post
Share on other sites
Quote:
Original post by Meta Adam
some code


dogage, dogheight and dogweight only exists in those functions you still have no way of setting age, height and weight(well at least I think you don't). This is probably what you are looking for:


class dog {
private:
int age, height, weight;
public:
void set_age(int dogage) {
age = dogage;
};
void bark() {
cout<< "Bark bark" << endl;
};
void set_height(int dogheight) {
height = dogheight;
};
void set_weight(int dogweight) {
weight = dogweight;
};
//I've added these. You need some way to access your private data too.
int get_age() {
return age;
};
int get_height() {
return height;
};
int get_weight() {
return weight;
};

dog();
~dog();
}



Quote:
Original post by Meta Adam
p.s. I forgot how to post code the right way.. what are the tags for it?

[ source ] and [ /source ] (without spaces)

EDIT: Damn you people post fast

Share this post


Link to post
Share on other sites
Quote:

Yea, but i dont understand why it couldnt just be..


One of the issues is you're seeing fairly simple examples (and one could argue that the classes you're presenting aren't really classes, just collections of data). However, keeping the accessor / mutator (sounds so much cooler that getter / setter) theme running...

Say you're programming an RTS. Each unit has a public health field. Everytime something damages a unit, it has code like this:

tank.health -= 10

Half way through your development you decide that units that are damaged more than 50% have reduced speed. Now you have to go through your code and find all 3-gazillion occurences of the above code, and add:

if(tank.health < tank.maxhealth/2)
tank.speed /= 2;

Instead, if you had a mutator, you'd just change the code in the mutator (ie in one place), and every single occurence now does the right thing.

HTH,
Jim.

Share this post


Link to post
Share on other sites
Quote:
Original post by Meta Adam
Yea, but i dont understand why it couldnt just be:
*** Source Showing data members as public ***


Well, it _can_ be. That's what makes the concept difficult. I was a longtime C programmer when I started to learn C++. The first thing that just baffled me was why you wanted to add all this complexity.

Why did these classes need methods? I have written functions and they work fine.

What's with this access protection stuff? I have declared variables and they work fine.

Making the data that a class holds private is a matter of methodology, not syntax. In other words, the code you posted works fine. However, what programmers discovered over the years of building massive applications with "top-down" languages like C was that it was really hard to manage and debug the code base.

The idea of C++ and being Object Oriented in general is that you can break your program's functionality into classes. The classes control their internals (the data) and it exposes functions that others can use to operate on them.

The string example given above is a classic. If you wrote a class that held a string for you, you would do so because managing character buffers is a pain, and prone to bugs. So you write this class, but if you simply left out the data in "public" for anyone to mess with, then you can't ever be certain the data in the string class still has any integrity. After all, any other class or function or method could come along and change the length of the string without changing the string data to match.

Instead you write public methods that make sure all operations performed are valid. They do some sanity checking, change the internal data, and will give it back to you with public accessors like get.

In a small class, the point can not be driven home. Your example makes the whole process of having private data with public accessors seem like extra and unnecessary work. That's why I balked so much when I read my first C++ book. The examples weren't compelling enough.

I am not belittling your example. Rather, I am reliving the feelings I had when I first read the chapter on data encapsulation in my first C++ book and said "What is this useful for again? It seems like more work."

That's the best answer I can give. The code you post works. However, it does not encapsulate the data. So any function that wants to change the dog's height, weight, or age can do so without anything to stop it. And if that's okay, then public is fine.

Share this post


Link to post
Share on other sites
In this specific example, it really doesn't matter: your class is a mere data aggregation. One typical design error people make is to make their member variables private and then hurry to write accessors for each and every one of them.

That's not a good idea.

In fact, it only serves to make things worse.

Sure, they will argue that it allows them to later change how things work (encapsulation) without having to modify external code (e.g. to add parameter checking...), but in practice, they tend to provide many more accessors than are really needed, and end up exposing way too much of their class' implementation details.

Yes, even knowing that your class has a data field named 'age' is a piece of information you are revealing to the world.

A better practice is to expose operations on the class rather than those kind of get/set accessors, and to write client code in terms of those operations rather than in terms of the data in the class. The only things that really need access to your data fields are display functions (and even then...) and GUI builder tools (so that they can set the properties on each GUI component from within the GUI building application, and have the components immediately change). Most of your code shouldn't need to access those data fields directly, and you should consider making code that does part of your class.

As a small example, instead of letting people manipulate the age of your dog, you could store the date of birth at construction and compute the age upon request... (though you could use a private variable to cache the computation... people don't have to know - that's why it is private; having a set_age function pretty much implies there is an age variable).

edit: building on JimPrice's example, instead of a set_health() function, your tank class might have take_damage() and get_repaired() functions. get_speed() might work from a base_speed member variable, accounting from the damage the tank has suffered. Abstracting things that way mean you never have to explicitely reference a variable.

One final minor nit, I'm personally fond of this syntax, when accessors are necessary (and, yes, they sometime are, just not as often as people seem to believe):

class Foo
{
Bar bar_;
public:
const Bar& bar() const // Note that the member function is const, so that
// it may work even on const Foo objects.
{
return bar_; // Return by const reference, disallows modification
// You may return basic types (e.g. int) by value.
}
Foo& bar(const Bar &value) // Take parameter by const reference, see above
{
bar_=value;
return *this; // Return the object itself as a reference
}
};



Returning the object as a reference allows chaining: f.foo(10).bar(20);, in a manner very similar to chained assignment f = g = h; (which is why operator= and its variants +=, -= ... do return *this; by reference too).

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny
Making things private is thus a way to protect your class invariant, as well as hiding implementation details by forcing people to use a specified interface (Encapsulation).


This is a common explanation, but in my opinion, it is backwards and counter-productive.

First of all, you are not protecting the invariants -- you are protecting the user of the class. You are protecting the user from changes to the interface of the class. If the user wants to fiddle with implementation details and suspend (temporarily, of course) the validity of the class invariants, then more power to him. The real problem is that if the implementation of the class is exposed, then every time the implementation changes (even by the smallest amount), the interface changes, and that could have serious consequences.

Second, the reason for hiding details is not to force the user to use the class in a certain way. The reason is to clear the interface of distractions and complication. An interface that exposes implementation details requires the user to understand those implementation details in order to use the class. An interface should expose only what is necessary to use the class. Anything more just makes the class harder to use. Besides, nobody likes to be forced to do anything.

Share this post


Link to post
Share on other sites
Quote:
generally I don't bother with get/set. A single overloaded access function for each property is enough:

int age();
void age(int);


That is Get/Set, just with a different set of function names!

Share this post


Link to post
Share on other sites
I'm growing tired of this quesion...
Read older forum topics, or [google]it, or read a book about it.

Please excuse my unusual grumpiness, I got horribly sun-burnt today!

Share this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
Second, the reason for hiding details is not to force the user to use the class in a certain way. The reason is to clear the interface of distractions and complication.


Exactly - it's to not force the user to use the class in the other way. ;)

Quote:
Besides, nobody likes to be forced to do anything.


Yeah, if going through your class' interface feels 'forced' for some reason, that's a smell that something is wrong. You should want to only do things in the prescribed manner. Especially if you own the code on both ends. :)

@leiavoia: There are two sides of the debate on accessors and mutators - one is the extent to which they are used, and the other is what they are called. I agree that sounds kind of silly, but there you have it. FWIW, my policy is:

- If there's an invariant to be maintained, then there's probably a better name that doesn't necessarily even mention the variable name.
- Having only one of {accessor, mutator} is better than having both, although still inferior to having methods that Do Something(TM).
- If I really really want to provide both methods, then I normally just make the member public instead - and leave a TODO refactoring comment. I've always found a way to make it work better (except in Python, where I often don't even try because the project just isn't ever going to get bigger than a couple hundred LOC anyway), just like I've never needed or wanted a goto (except of course in languages where that's all you've got - and although I appreciate that it must make life a lot easier for some, I can only conclude that they're doing something radically different...).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement