Wednesday, May 30, 2007

Never specify public or protected member data in a class

Never specify public or protected member data in a class.
------------------------------------------------------------
The use of public variables is discouraged for the following reasons:

A public variable represents a violation of one of the basic principles of object-oriented programming, namely, encapsulation of data. For example, if there is a class of the type BankAccount, in which account_balance is a public variable, the value of this variable may be changed by any user of the class. However, if the variable has been declared private, its value may be changed only by the member functions of the class. [Not completely true. If a class has a member function which returns a reference to a data member, variables may be modified. This is avoided by following Rule 29.]
An arbitrary function in a program can change public data which may lead to errors that are difficult to locate.
If public data is avoided, its internal representation may be changed without users of the class having to modify their code. A principle of class design is to maintain the stability of the public interface of the class. The implementation of a class should not be a concern for its users.
The use of protected variables in a class are not recommended, since its variables become visible to its derived classes. The names of types or variables in a base class may then not be changed since the derived classes may depend on them. If a derived class, for some reason, must access data in its base class, one solution may be to make a special protected interface in the base class, containing functions which return private data. This solution would not imply any degradation of performance if the functions are defined inline.

The use of structs is also discouraged since these only contain public data. In interfaces with other languages (such as C), it may, however, be necessary to use structs.

Exception to Rule 22
In interfaces with other languages (such as C), it may be necessary to use structs having public data.
Example 22: The correct way to encapsulate data so that future changes are possible.
This shows why member functions should be used to access data (instead of using direct references). This usage provides long term advantages, since internal data in a class may be changed without having to modify interfaces and to re-write the code which uses them.

// Original class:

class Symbol {};
class OldSymbol : public Symbol {};

class Priority
{
public:
// returns pd
int priority();

// returns symbol
class Symbol* getSymbol() const;
// ...
private:
int pd;
OldSymbol symbol;
};


// Modified class:
// The programmer has chosen to change the private data from an int
// to an enum. A user of the class `Priority' does not have to change
// any code, since the enum return-value from the member function
// priority() is automatically converted to an int.

class Symbol {};
class NewSymbol : public Symbol {};
enum Priority { low, high, urgent };

class Priority
{
public:
// Interface intact through implicit cast, returns priority_data
Priority priority();

// Interface intact, object of new subclass to symbol returned
class Symbol* getSymbol() const;
// ...

private:
Priority priority_data; // New representation/name of internal data
NewSymbol symbol;
};

No comments: