Tuesday 10 February 2009

Nested Classes

Classes can be defined inside other classes. Classes that are defined inside other classes are called nested classes. Nested classes are used in situations where the nested class has a close conceptual relationship to its surrounding class. For example, with the class string a type string::iterator is available which will provide all characters that are stored in the string. This string::iterator type could be defined as an object iterator, defined as nested class in the class string.

A class can be nested in every part of the surrounding class: in the public, protected or private section. Such a nested class can be considered a member of the surrounding class. The normal access and rules in classes apply to nested classes. If a class is nested in the public section of a class, it is visible outside the surrounding class. If it is nested in the protected section it is visible in subclasses, derived from the surrounding class , if it is nested in the private section, it is only visible for the members of the surrounding class.

The surrounding class has no special privileges with respect to the nested class. So, the nested class still has full control over the accessibility of its members by the surrounding class. For example, consider the following class definition:

    class Surround
{
public:
class FirstWithin
{
int d_variable;

public:
FirstWithin();
int var() const;
};
private:
class SecondWithin
{
int d_variable;

public:
SecondWithin();
int var() const;
};
};
inline int Surround::FirstWithin::var() const
{
return d_variable;
}
inline int Surround::SecondWithin::var() const
{
return d_variable;
}
In this definition access to the members is defined as follows:
  • The class FirstWithin is visible both outside and inside Surround. The class FirstWithin therefore has global scope.
  • The constructor FirstWithin() and the member function var() of the class FirstWithin are also globally visible.
  • The int d_variable datamember is only visible to the members of the class FirstWithin. Neither the members of Surround nor the members of SecondWithin can access d_variable of the class FirstWithin directly.
  • The class SecondWithin is only visible inside Surround. The public members of the class SecondWithin can also be used by the members of the class FirstWithin, as nested classes can be considered members of their surrounding class.
  • The constructor SecondWithin() and the member function var() of the class SecondWithin can also only be reached by the members of Surround (and by the members of its nested classes).
  • The int d_variable datamember of the class SecondWithin is only visible to the members of the class SecondWithin. Neither the members of Surround nor the members of FirstWithin can access d_variable of the class SecondWithin directly.
  • As always, an object of the class type is required before its members can be called. This also holds true for nested classes.
If the surrounding class should have access rights to the private members of its nested classes or if nested classes should have access rights to the private members of the surrounding class, the classes can be defined as friend classes.

The nested classes can be considered members of the surrounding class, but the members of nested classes are not members of the surrounding class. So, a member of the class Surround may not access FirstWithin::var() directly. This is understandable considering the fact that a Surround object is not also a FirstWithin or SecondWithin object. In fact, nested classes are just typenames. It is not implied that objects of such classes automatically exist in the surrounding class. If a member of the surrounding class should use a (non-static) member of a nested class then the surrounding class must define a nested class object, which can thereupon be used by the members of the surrounding class to use members of the nested class.

For example, in the following class definition there is a surrounding class Outer and a nested class Inner. The class Outer contains a member function caller() which uses the inner object that is composed in Outer to call the infunction() member function of Inner:

    class Outer
{
public:
void caller();

private:
class Inner
{
public:
void infunction();
};
Inner d_inner; // class Inner must be known
};
void Outer::caller()
{
d_inner.infunction();
}
The mentioned function Inner::infunction() can be called as part of the inline definition of Outer::caller(), even though the definition of the class Inner is yet to be seen by the compiler. On the other hand, the compiler must have seen the definition of the class Inner before a data member of that class can be defined.

0 comments: