Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Notes on Nested Classes | UNIX Programming | CS 501, Study notes of Deductive Database Systems

Material Type: Notes; Class: Unix Programming; Subject: Computer Science; University: Emporia State University; Term: Fall 2004;

Typology: Study notes

Pre 2010

Uploaded on 08/06/2009

koofers-user-jtv
koofers-user-jtv 🇺🇸

10 documents

1 / 10

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
zNext chapter
zPrevious chapter
zTable of contents
Chapter 16: Nested Classes
We're always interested in getting feedback. E-mail us if you like this guide, if you think that
important material is omitted, if you encounter errors in the code examples or in the
documentation, if you find any typos, or generally just if you feel like e-mailing. Send your
email to Frank Brokken.
Please state the document version you're referring to, as found in the title (in this document:
5.2.4) and please state the paragraph you're referring to.
All mail received is seriously considered, and new (sub)releases of the Annotations will
normally reflect your suggestions for improvements. Except for the incidental case, I will
normally not acknowledge the receipt of suggestions for improvements. Please don't
interpret this as me showing lack of appreciation.
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 the surrounding class. For example, with the class string a type string::iterator is available
which will provide all elements (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 (see chapter 13), if it is nested in the private section, it is only
visible for the members of the surrounding class.
The surrounding class has no 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
{
Pa
g
e 1 of 10C++ Annotations Version 5.2.4
11/12/2004htt
p
://docs.linux.cz/
p
ro
g
rammin
g
/c++/www.icce.ru
g
.nl/documents/c
p
lus
p
lus/c
p
lus
p
lus16...
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Notes on Nested Classes | UNIX Programming | CS 501 and more Study notes Deductive Database Systems in PDF only on Docsity!

z Next chapter

z Previous chapter

z Table of contents

Chapter 16: Nested Classes

We're always interested in getting feedback. E-mail us if you like this guide, if you think that

important material is omitted, if you encounter errors in the code examples or in the

documentation, if you find any typos, or generally just if you feel like e-mailing. Send your

email to Frank Brokken.

Please state the document version you're referring to, as found in the title (in this document:

5.2.4) and please state the paragraph you're referring to.

All mail received is seriously considered, and new (sub)releases of the Annotations will

normally reflect your suggestions for improvements. Except for the incidental case, I will

normally not acknowledge the receipt of suggestions for improvements. Please don't

interpret this as me showing lack of appreciation.

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 the surrounding class. For example, with the class string^ a type string::iterator^ is available

which will provide all elements (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 (see chapter 13), if it is nested in the private section, it is only

visible for the members of the surrounding class.

The surrounding class has no 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 {

return (d_variable); } }; private: class SecondWithin { int d_variable;

public: SecondWithin(); int var() const { return (d_variable); } }; };

In this definition access to the members is defined as follows:

z The class FirstWithin^ is visible both outside and inside Surround. The class FirstWithin^ has

therefore global scope.

z The constructor FirstWithin()^ and the member function var()^ of the class FirstWithin^ are

also globally visible.

z The int^ d_variable^ datamember is only visible for the members of the class FirstWithin.

Neither the members of Surround^ nor the members of SecondWithin^ can access the d_variable

of the class FirstWithin directly.

z The class SecondWithin^ is visible only 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.

z 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).

z The int d_variable datamember of the class SecondWithin is only visible for the members of

the class SecondWithin. Neither the members of Surround^ nor the members of FirstWithin^ can

access the d_variable of the class SecondWithin directly.

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 (see section 16.3).

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. The nested classes are only available as typenames. They

do not imply containment as objects by the surrounding class. If a member of the surrounding class

should use a (non-static) member of a nested class then a pointer to a nested class object or a nested

class datamember must be defined in the surrounding class, which can thereupon be used by the

members of the surrounding class to access 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:

members of the class FirstWithin^ there is no need to refer explicitly to the scope.

What about the members of the class SecondWithin? The classes FirstWithin^ and SecondWithin^ are

both nested within Surround, and can be considered members of the surrounding class. Since members

of a class may directy refer to each other, members of the class SecondWithin can refer to (public)

members of the class FirstWithin. Consequently, members of the class SecondWithin^ could refer to

the epoch^ member of FirstWithin^ as

FirstWithin::epoch

16.2: Declaring nested classes

Nested classes may be declared before they are actually defined in a surrounding class. Such forward

declarations are required if a class contains multiple nested classes, and the nested classes contain

pointers to objects of the other nested classes.

For example, the following class Outer contains two nested classes Inner1 and Inner2. The class

Inner1 contains a pointer to Inner2 objects, and Inner2 contains a pointer to Inner1 objects. Such

cross references require forward declarations:

class Outer { private: class Inner2; // forward declaration

class Inner { Inner2 *pi2; // points to Inner2 objects }; class Inner { Inner1 *pi1; // points to Inner1 objects }; };

16.3: Accessing private members in nested classes

In order to allow nested classes to access the private members of the surrounding class; to access the

private members of other nested classes; or to allow the surrounding class to access the private members

of nested classes, the friend keyword must be used. Consider the following situation, in which a class

Surround has two nested classes FirstWithin and SecondWithin, while each class has a static data

member int variable:

class Surround { static int s_variable; public: class FirstWithin { static int s_variable;

public: int value(); };

int value(); private: class SecondWithin { static int s_variable;

public: int value(); }; };

If the class Surround should be able to access the private members of FirstWithin and SecondWithin,

these latter two classes must declare Surround^ to be their friend. The function Surround::value()^ can

thereupon access the private members of the nested classes. For example (note the friend^ declarations

in the two nested classes):

class Surround { static int s_variable;

public: class FirstWithin { friend class Surround;

static int s_variable;

public: int value(); }; int value() { FirstWithin::s_variable = SecondWithin::s_variable; return (s_variable); } private: class SecondWithin { friend class Surround;

static int s_variable;

public: int value(); }; };

Now, in order to allow the nested classes to access the private members of the surrounding class, the

class Surround must declare the nested classes as friends. The friend keyword may only be used when

the class that is to become a friend is already known as a class by the compiler, so either a forward

declaration of the nested classes is required, which is followed by the friend declaration, or the friend

declaration follows the definition of the nested classes. The forward declaration followed by the friend

declaration looks like this:

class Surround { class FirstWithin;

some friend^ declarations. In order to allow FirstWithin^ to access SecondWithin's private members

nothing but a friend declaration in SecondWithin is required. However, to allow SecondWithin to

access the private members of FirstWithin the friend class SecondWithin declaration cannot be

plainly given in the class FirstWithin, as the definition of SecondWithin^ has not yet been given. A

forward declaration of SecondWithin^ is required, and this forward declaration must be given in the class

Surround, rather than in the class FirstWithin. Clearly, the forward declaration class SecondWithin

in the class FirstWithin^ itself makes no sense, as this would refer to an external (global) class

FirstWithin. But the attempt to provide the forward declaration of the nested class SecondWithin

inside FirstWithin as class Surround::SecondWithin also fails miserably, with the compiler

issuing a message like

Surround' does not have a nested type namedSecondWithin'

The proper procedure here is to declare the class SecondWithin in the class Surround, before the class

FirstWithin is defined. Using this procedure, the friend declaration of SecondWithin is accepted

inside the definition of FirstWithin. The following class definition allows full access of the private

members of all classes by all other classes:

class Surround { class SecondWithin;

static int s_variable;

public: class FirstWithin { friend class Surround; friend class SecondWithin;

static int s_variable;

public: int value() { Surround::s_variable = SecondWithin::s_variable; return (s_variable); } }; friend class FirstWithin;

int value() { FirstWithin::s_variable = SecondWithin::s_variable; return (s_variable); } private: class SecondWithin { friend class Surround; friend class FirstWithin;

static int s_variable;

public: int value() {

Surround::s_variable = FirstWithin::s_variable; return (s_variable); } }; friend class SecondWithin; };

16.4: Nesting enumerations

Enumerations may also be nested in classes. Nesting enumerations is a good way to show the close

connection between the enumeration and its class. In the class ios^ we've seen values like ios::beg^ and

ios::cur. These values are (i.e., in the current Gnu C++ implementation) defined as values in the

seek_dir enumeration:

class ios : public _ios_fields { public: enum seek_dir { beg, cur, end }; };

For illustration purposes, let's assume that, a class DataStructure may be traversed in a forward or

backward direction. Such a class can define an enumeration Traversal having the values forward and

backward. Furthermore, a member function setTraversal() can be defined requiring either of the two

enumeration values. The class can be defined as follows:

class DataStructure { public: enum Traversal { forward, backward }; setTraversal(Traversal mode); private: Traversal d_mode; };

Within the class DataStructure^ the values of the Traversal^ enumeration can be used directly. For

example:

void DataStructure::setTraversal(Traversal mode) { d_mode = mode; switch (d_mode) { forward: break;

enum EmptyEnum {};

int main() { try { throw EmptyEnum(); } catch (EmptyEnum) { cout << "Caught empty enum\n"; } } /* Generated output: Caught empty enum */

z Next chapter

z Previous chapter

z Table of contents