Skip over navigation

Contents

Classes in C++

Inheritance

Problems

Problems

An important feature of object-oriented programming languages is inheritance: the ability to create derived classes. Consider the following class definition:


class Polygon
{
	private:
		int num_sides;
	public:
		int get_num_sides() {return num_sides;}
		Polygon(int ns=3) {num_sides = ns;}
};

You might like to create a new class called Quad to represent a 4-sided figure; but since this is a type of polygon, it shares some of the same properties. In this simple example, num_sides might be a convenient property for the Quad class to keep track of, so you might choose to derive class Quad from class Polygon:


class Quad : public Polygon
{
	private:
		double side_length[4];
	public:
		double get_perimeter();
		Square(double side1, double side2, 
		       double side3, double side4);
		~Square();
}
double Quad::get_perimeter() {
	double perim = 0;
	for(int i = 0; i < 4; i++) 
		perim += side_length[i];	// sum the sides
	return perim;
}
Quad::Quad(double side1, double side2, double side3, double side4) : Polygon(4)
{
	side_length[0] = side1;
	side_length[1] = side2;
	side_length[2] = side3;
	side_length[3] = side4;
}
Quad::~Quad() : ~Polygon() {delete [] side_length;}

Quad is called a subclass of its superclass Polygon. Creating a derived class is similar to creating a new class, except you use the colon operator to indicate the superclass in the declaration, in the constructor, and in the destructor. Notice that in the notation for the constructor, the superclass's constructor is called with argument 4.

Any instance of a subclass has all the same member functions and data members as its superclass. Therefore Quad has a private data member num_sides and member function get_num_sides() (as well as the constructor Polygon() ). However, Quad cannot directly access its num_sides data member, even within the class definition, because the variable was declared to be private in the definition of Polygon. A superclass's private data member can only be accessed through the superclass's public member functions. If I wanted num_sides to be accessible to the Quad subclass, but still have the other properties of a private data member within Quad, I would have to declare num_sides as a protected variable in its superclass, Polygon. The protected keyword is used for any variable (or function) that should be directly accessible to subclasses, but should otherwise behave as a private data member.

Multiple inheritance is also allowed in C++. In the class definition, separate the superclasses by commas:


class MySubclass : public Superclass1, public Superclass2
{
	/* class definition */
};

Be sure to use the scope operator generously; if two classes have the same variable name or function name, you need to be specific. Consider the following:


class Mom{
	protected: int age;
	/* the rest of class Mom */
};

class Dad{
	protected: int age;
	/* the rest of class Dad */
};

class Kid : public Mom, public Dad
{
	public: int get_age() {return age;}	// note the problem....
	/* rest of class Kid */
};

Class Kid attempts to access variable age in its get_age() function; but it is unclear whether this means Dad::age or Mom::age, so it is necessary to specify. A similar problem occurs when two superclasses share the same base class. Suppose there were a base class Grandparent with protected data member height, and Mom and Dad were subclasses of Grandparent:


class Grandparent{
	protected: int height;
	/* rest of class */
};

class Mom : public Grandparent { /* class definition */ };
class Dad : public Grandparent { /* class definition */ };

class Kid : public Mom, public Dad
{
	public: int get_height() {return height;}
};

The compiler will not like the ambiguity in class Kid. To fix this, include the word virtual in deriving Mom and Dad:


class Mom : virtual public Grandparent {};
class Dad : virtual public Grandparent {};

Then the compiler will have class Kid inherit only one subclass Grandparent. In addition, virtual classes have some other functionalities beyond the scope of this introduction. Having stated the problems and solutions of multiple inheritance, it's worth noting that it can generally be avoided by using composition; that is, by using would-be superclasses as data member objects:


class Kid
{
	private: 
		Mom m;
		Dad d;
	public:
		get_mom_height() {return m.height;}
		get_dad_height() {return d.height;}
};

This changes the structure of class Kid, but it may simplify programs by avoiding confusion.

The last fundamental topic about classes essential for C++ programming is that of class templates. Similar to function templates, class templates are useful if the data type of some component is not yet known, or if many data types will be used for the same kind of object. Consider the following class template that contains an array of some unknown type:


template <class T>
class Array
{
	private:
		T array[MAX_VAL];
		int current_element;
	public:
		Array(int ce = 0) {current_element = ce;}
		void set_index(int i) 
		{if ((i < MAX_VAL) && (i >= 0) 
			current_element = i;}
		void set_curr(T t) {array[current_element] = t;}
		T get_curr() {return array[current_element];}
};

Different types of Array objects can be created:


Array<float> Float_array;
Array<char> Char_array;

To define member functions outside the class specification, use the syntax:


template<class T>
Array<T>::Array(int ce = 0) {current_element = ce;}	// constructor

template<class T>
void Array<T>::set_index(int i) {
	if ((i < MAX_VAL) && (i >= 0) current_element = i;
}

etc.

If you need class templates for "containers" (e.g. arrays, stacks, linked lists, or "vectors"), then before programming them yourself, look into the C++ Standard Template Library (STL); it contains class templates that can be very useful.

Follow Us