C++ Types Not Found in C
The Class Type
The class type replaces
structs as the dominant means for declaring a user-defined
data type. Like a struct a class has a set of named data elements.
These data elements are called its instance variables.
Unlike a C struct, a class also has a set of operations, called
methods, that manipulate the class's data elements.
The data elements and methods that make up a class are called
its members.
We will use the following class definition of an array throughout
this section to illustrate the various facets of the class type:
const int ArraySize = 12; // default size
class IntArray {
public:
// operations performed on arrays
IntArray( int size = ArraySize );
~IntArray();
int getValue( int index );
void setValue( int index, int value );
int getSize();
protected:
void checkBounds( int index );
// internal data representation
int size;
int *data;
};
This array class provides several services that the normal array type
does not provide:
- The size of the array can be determined at run-time
- The class range-checks the array index
Data Members
- Like a variable declaration, but initializers are not allowed.
- A class object can be declared as a data member only if its class
definition has already been seen. For example, the following class
definition is illegal:
class Stack {
int topStack;
Stack stack; // illegal--class definition not yet complete
};
- A pointer to a class object can be declared as a data
member as long as a forward declaration of the class has been seen.
For example, the following class definition is legal:
class Stack; //forward declaration
class Stack {
int topStack;
Stack *stack; // legal--a forward class declaration has been seen
};
The following is also legal because a class is considered declared
as soon as its class name is seen:
class tree_node {
tree_node *left_child;
tree_node *right_child;
};
Member Functions
- The public member functions of a class are called the class
interface.
- Member functions defined outside the class body must be
prefixed by the class's name and two colons (::). For example:
IntArray::IntArray( int sz ) {
// allocate an integer array of 'size' elements.
// new returns a pointer to this array or 0
// 0 indicates the program has exhausted its
// available memory: a generally fatal error
size = sz;
data = new int[size];
for ( int ix=0; ix < sz; ix++ )
data[ix] = 0;
}
void IntArray::checkBounds (int index) {
if (index < 0) {
printf("An array index is out of bounds. Its value is %d\n", index);
exit(1);
}
if (index >= size) {
printf("An array index exceeds the bounds of its array. The size\n");
printf("of the array is %d but the value of the index is %d\n",
size, index);
exit(1);
}
}
int IntArray::getValue (int index) {
checkBounds(index);
return data[index];
}
void IntArray::setValue (int index, int value) {
checkBounds(index);
data[index] = value;
}
int IntArray::getSize() { return size; }
IntArray::~IntArray() { delete [] data; }
- Member functions have full access privilege to all the members of
the class, be they public, protected, or private.
Access Privileges
- public: The class member is accessible from anywhere within
an application. Typically only methods should be public.
- protected: A protected member may be inherited by a subclass
and may be accessed by any of the class's methods. However, it may not be
accessed anywhere else in the application. Data members should typically
be declared protected.
- private: A private member may only be accessed by the class's
member functions. The member is not inherited by any subclasses.
- Prefer protected to private: Protected makes inheritance possible.
Private kills inheritance. It is very rare that you would want a
class to contain an instance variable but not want a subclass to
contain the same instance variable.
- Class members are private by default.
- Information hiding: By declaring data members as protected, you
hide the class's implementation from the application. Consequently,
the class's implementation can be altered without requiring any
alterations to the application.
- If desired, access to protected data members can be efficiently
provided via inline accessor methods. IntArray's GetSize
method is an example of an inline, accessor method.
- friend: The friend keyword gives an outside class access to
a class's protected and private members. For example:
class Dlist;
class Dlnode {
friend Dlist;
protected:
...
};
The friend declaration gives Dlist access to all of Dlnode's variables
and methods. You use a friend declaration to selectively give outsiders
access to a class's variables/method. Typically this is done when the
outsider needs to work closely with the class or even "own" the class.
For example, the only place a Dlnode will presumably be used is in
a Dlist so in effect the Dlist class "owns" the Dlnode class.
The Implicit this Pointer
- Passed as an implicit argument to every member method.
- this is a pointer to the object through which this method
was invoked. Consequently, the following two statements are equivalent:
int getSize() { return size; }
int getSize() { return this->size; }
- Common uses for this
- To call a method in another object and pass a reference to
this object as an argument. For example, if this object is
to be added to a hash table object called object_table,
one might add it with the call:
object_table.add(this);
- To return a pointer to this object. We will see later
why returning a pointer to oneself is sometimes useful.