c++ question

Started by
6 comments, last by Oxyd 14 years, 10 months ago
So.. I read in c++ manuals, that when creating classes, you should make the members private if you want to control "who" can access the members. Why? I mean, I am the one who codes the code, and if I don't want class X to access class Y members, I just won't code it. What's the point making private members and making public Get (and maybe Set) methods? Probably a stupid question, but I'm just wondering.
Advertisement
It's to signal intent. Structure is not for the benefit of the program, but for the programmer(s).
Encapsulation/data hiding (making things private) is a real big deal in object oriented programming. If you only have afew classes, you kindof have a point that your just hiding it from yourself, but it's still poor design. On larger projects - say 100+ classes - with multiple people working in different areas, having a good clean interface to your classes is essential. If people can only use your class one way, and not have access to it's internals, it ultimately prevents bugs from people using your class in unexpected ways, or accidentally changing something they shouldn't.
Quote:Original post by Funguz
So.. I read in c++ manuals, that when creating classes, you should make the members private if you want to control "who" can access the members. Why?


There are a couple of (related) reasons.

1. Objects have invariants. Often the values of the member variables will be related to one another in some way. If direct access is permitted to the members of such an object, an invariant may be broken, which would be a bug in your program.

However, some objects are merely collections of data and may not have any invariants. IMVHO, direct access to members of these objects usually isn't a big deal.

2. However, making member objects private adds a level of encapsulation and may protect you from future implementation changes. Let's look at a really silly example. Say you have an object that stores the name of a Person.

class Person{    public:        string name;};


All over your code you use person.name to access the name of a Person. But you soon discover that it would actually be better to store the parts of a Person's name individually.

class Person{    public:        vector<string> names; // first, middle and family name(s)}


Now you have to go and change all your code to deal with person.names instead of person.name

But if we instead started with:

class Person{    public:        string Name() const; // returns name_    private:        string name_;};


we're still ok if we change the private data:

class Person{    public:        string Name() const; // joins the strings in names_ together    private:        vector<string> names_;};


We don't have to go and replace all the places where we accessed a person's .name directly. Instead we only have to change one piece of code -- the Person::Name() function.

Quote:
I mean, I am the one who codes the code, and if I don't want class X to access class Y members, I just won't code it.

Will you always be the only one with access to your code? Where are these rules written down? Will you remember to obey them 6 months down the road?

Of course, you could add a comment, but making a variable private is a stronger kind of comment, one that the compiler can help you to enforce.

Finally, some people would say that having too many Get/Set methods is a sign of a potentially bad design; an object in the OO sense is defined by it's data and behaviour. Lots of Get/Set methods might imply that you've concentrated too much on the data part, but not enough on the behaviour part. In the end, you'll make up your own mind with the benefit of more experience.
The "who" in the book doesn't refer to programmers or end-users or any sort of human at all. It refers to which parts of code can use, depend up, and mess up the variable. If you make it private, that "who" is only the class the variable resides in. By making it private, you have ensured that if you have a problem relating to that variable, you know which class it occurs in. It's easier to make guarantees about a variable if a limited subsection gets access to it. It's easier to modify the implementation details if only one class depends directly upon it.

Also, Get and Set methods are often less than ideal. Certainly, there are times for them, but often you should be using higher-level concepts. For example, if you made a vector class (variable-length array, essentially, if you didn't know already), it would be stupid to have a SetLength function - length should be automatically kept track of when elements are added or removed from the vector. GetLength makes sense, but write access to length is only going to cause issues. Don't just blindly make private variables and public Getters and Setters.
Personally, I think when you have a private variable and a setVar and getVar method that does nothing else then setting and returning the variable, it's a bit waste of space. However, if you want a get only, or if the set function should validate the input first or perform some tasks when it changes, it makes sense to not allow direct access. Saying that brings up a reason to always do so, maybe you don't use validation right now, but you will in the future. If you use setVar functions from the beginning, when you later want to do validation of the input, or perform some calculations before setting it, you only need to change the set function. If you later find out a public variable has to be changed to a private one with get/set function, you will end up going through your whole project to change every use of the variable.

As for the question why, of course you could make everything public in classes used internally only, and only keep data of the outside classes that the user of your engine actually uses private. I think your code will easier turn into a mess then however. For 2 classes that are very closely related, you can always make them friends so you can access their private variables if you really want to.
Quote:Original post by Funguz
Why? I mean, I am the one who codes the code, and if I don't want class X to access class Y members, I just won't code it.


That's rarely the case in the real world simply because of the complexity of most modern programs. But even if you are the only person working on a program, it still helps. You write some chunk of code, then go off and work on other things for 6 months or a year, then come back and need to work on the first chunk of code again. Even if you have good comments and documentation of that code you're effectively a stranger to it - you don't remember what exactly you were thinking when you wrote it or anything like that.

Quote:What's the point making private members and making public Get (and maybe Set) methods? Probably a stupid question, but I'm just wondering.


It abstracts information so that the user of the class doesn't need to worry about how the class works, but only about what it does. Even if you're the only user this is helpful, because it lets you change how a class works without having to go back and modify every place the class is used.

It also tends to make more sense when you start dealing with more "real" classes instead of the little example things they have to messing with in books. Take for example something I was working on yesterday

class XmlFile  : public boost::noncopyable{public:  enum Encoding  {    XML_ENCODING_UNK,    XML_ENCODING_UTF8,    XML_ENCODING_LEGACY  };  XmlFile(const std::string& filename, Encoding encoding = XML_ENCODING_UNK);  ~XmlFile( );  const std::string& getFilename( ) const;  void setFilename(const std::string& filename);  void load(const std::string& filename, Encoding encoding = XML_ENCODING_UNK);  void save(const std::string& filename = "", bool makeActive = false);  std::string getString(const std::string& key) const;  SInt getInt(const std::string& key) const;  double getDouble(const std::string& key) const;  bool getBool(const std::string& key) const;  void setString(const std::string& key, const std::string& val);  void setInt(const std::string& key, SInt val);  void setDouble(const std::string& key, double val);  void setBool(const std::string& key, bool val);private:  // intentionally removed  };


At the moment this class is a wrapper around the TinyXML parser. But you don't know that, and you don't need to know that. I could change the implementation to use the Xerces parser, a custom written XML parser, or anything and anyone who uses the class doesn't have to change a thing.
Look at Python, it doesn't have this private thing. (Okay, it can mangle names, but let's ignore that for now.) Python programmers usually prefix their names with a _ if they want to let the world know that the variable is not supposed to be touched outside the "owning" code (be it a module or a class or whatever).

Python, however, also has properties, so it doesn't have this trap the_edd mentioned. Suppose you make a class to store a person's information and leave name as a publicly-accessible variable -- nothing wrong with that, it's Python:
class Person(object):    def __init__(self, name):        self.name = name...p = Person('John Doe')print p.name  # No troubling us with accessor functions, just access it directly
But let's suppose that you find out it would, in fact, be handier to store the name by parts. Well, let's just change the attribute .name from being an exposed variable to a property!
class Person(object):    def __init__(self, name):        self.setName(name)    def getName(self):        return ' '.join(self._name)    def setName(self, newName):        self._name = newName.split(' ')    name = property(getName, setName)...# Client code remains the same!p = Person('John Doe')print p.name  # It looks like we're accessing a variable, but in fact a function will be called
Problem is, C++ doesn't provide you with this luxury that many languages do. So if you're writing C++, you need to be careful and think ahead of time -- stuff changes and the more encapsulated your code is, the less painful the changes are.

This topic is closed to new replies.

Advertisement