Main

Lecture 12

Thinking in C++, vol. 1, Chapter 5

OO concepts: encapsulation, implementation hiding

Exercises in the usual repository, lecture12/ subdirectory

Access control

Public, protected, and private class data members and methods

public

The most open level of data hiding is public. Anything that is public is available to all derived classes of a base class, and the public variables and data for each object of both the base and derived class is accessible by code outside the class. Everything following is public until the end of the class or another data hiding keyword is used.

In general, a well-designed class will have no public fields--everything should go through the class's functions.

protected

Variables and functions marked protected are inherited by derived classes; however, these derived classes hide the data from code outside of any instance of the object. Keep in mind, even if you have another object of the same type as your first object, the second object cannot access a protected variable in the first object. Instead, the second object will have its own variable with the same name, but not necessarily the same data.

private

Functions and variables marked private are not accessible by code outside the specific object in which that data appears. Private variables and functions are not inherited by derived classes.

Public, protected, and private inheritance

  1. class A
  2. {
  3. public:
  4.     int x;
  5. protected:
  6.     int y;
  7. private:
  8.     int z;
  9. };

1. Public inheritance: Is-a relationship Everywhere where A is needed, B can be passed.

  1. class B : public A
  2. {
  3.     // x is public
  4.     // y is protected
  5.     // z is not accessible from B
  6. };
  7.  
  8. 2. Protected inheritance: implemented-in-terms-of relationship. Rarely useful.
  9.  
  10. (:source lang=c++ linenum tabwidth=4:)[@
  11. class C : protected A  
  12. {
  13.     // x is protected
  14.     // y is protected
  15.     // z is not accessible from C
  16. };

3. Private inheritance: implemented-in-terms-of relationship. Useful for traits (which we haven't covered yet).

  1. class D : private A
  2. {
  3.     // x is private
  4.     // y is private
  5.     // z is not accessible from D
  6. };

Only members/friends of a class can see private inheritance, and only members/friends and derived classes can see protected inheritance.

Note that C-style casts allow casting a derived class to a protected or private base class in a defined and safe manner, as well as casting a base class to a derived class. This should be avoided at all costs, because it can make code dependent on implementation details. This can be prevented by using class handles as explained a bit later.

Friends

A class can allow another class to access its protected and private members by declaring it as a friend class or struct.

Example: Suppose we have a class Farmer that needs to access a Sheep's wool, but the Sheep's wool is a private data member. We could add the Farmer class as a friend of Sheep.

More Friend examples.

Class handles -- really hiding a class

Suppose your Cheshire class declaration must remain as private as possible, i.e., only the public members should be visible to anyone. Normally you would have a cheshire.hpp header file defining the Cheshire class, but then you will expose the types and names of protected and private variables and methods and they may reveal implementation details and may be accessed maliciously.

  1. #ifndef CHESHIREHANDLE_H
  2. #define CHESHIREHANDLE_H
  3.  
  4. class CheshireHandle {
  5.   struct Cheshire; // Class declaration only
  6.   Cheshire* smile;
  7. public:
  8.   void initialize();
  9.   void cleanup();
  10.   int read();
  11.   void change(int);
  12. };
  13. #endif // CHESHIREHANDLE_H

Assignment 5 will be out today

Unless you are Chuck Norris, start early.

Green Marinee theme adapted by David Gilbert, powered by PmWiki