Lesson Home

Inheritance

 

Introduction to Inheritance

 

Class Parenting

The ability to use already created classes is one of the strengths of C++. If you have a ready made class, you can construct a new one using the existing characteristics. Inheritance is the ability to create an object using, or based on, another. The new or inherited object is also said to derive from the other class.

There are various ways you can inherit a class: using an operating system object, basing an object on an existing C++ class, or creating a class from a Microsoft .NET Framework class. To start, you should define a class. This means that it should have functionality, valuable properties, and behaviors that other classes can use with little concern as to how the class is built, but trusting that it can handle the desired assignment of a parent.

Here is an example of a class called CRectangle: 

Header File: Rectangle.h
#pragma once

public __gc class CRectangle
{
private:
	double length;
	double height;
public:
	CRectangle(void);
	CRectangle(double L, double H);
    	void setDimensions(double L, double H);
	
    	double Perimeter();
	double Area();
	
public:
	__property void   set_Length(double L);
   	__property double get_Length();	
	__property void   set_Height(double H);
	__property double get_Height();
};

Here is the source file:

Source File: Rectangle.cpp
#include "StdAfx.h"
#include ".\rectangle.h"
#using <mscorlib.dll>

CRectangle::CRectangle(void)
	: length(0.00), height(0.00)
{
}

CRectangle::CRectangle(double L, double H)
	: length(L), height(H)
{
}

void CRectangle::setDimensions(double L, double H)
{
    	set_Length(L);
	set_Height(H);
}

double CRectangle::Perimeter()
{
	return 2 * (Length + Height);
} 
double CRectangle::Area()
{
	return Length * Height;
}

void CRectangle::set_Length(double L)
{
	length = (L < 0) ? 0 : L;
}

double CRectangle::get_Length()
{
	return length;
}

void CRectangle:: set_Height(double H)
{
	height = (H < 0) ? 0 : H;
}

double CRectangle::get_Height()
{
	return height;
}

To test the class, we can declare a CRectangle variable in the _tmain() function. We will also use the class' properties to make sure they respond:

// This is the main project file for VC++ application project 
// generated using an Application Wizard.

#include "stdafx.h"
#include ".\rectangle.h"

#using <mscorlib.dll>

using namespace System;

void ShowCharacteristics(CRectangle*);

int _tmain()
{
    	// TODO: Please replace the sample code below with your own.
	CRectangle *rect = new CRectangle(25.55, 20.82);

	ShowCharacteristics(rect);

    	Console::WriteLine(S"");
	return 0;
}

void ShowCharacteristics(CRectangle* R)
{
	Console::WriteLine(S"Rectangle Characteristics");
	Console::WriteLine(S"Length:    {0}", __box(R->Length));
	Console::WriteLine(S"Height:    {0}", __box(R->Height));
	Console::WriteLine(S"Perimeter: {0}", __box(R->Perimeter()));
	Console::WriteLine(S"Area:      {0}", __box(R->Area()));
}

This would produce:

Rectangle Characteristics
Length:    25.55
Height:    20.82
Perimeter: 92.74
Area:      531.951

Press any key to continue

Class Derivation

Once you have a defined class, you can apply its behavior as the starting point of another class. The basic syntax on inheriting from a class is:

[AccessLevel] __gc structORclass NewClass : AccessLevel ParentClass

If you want the class to be accessed by other assemblies, you can start by specifying the optional public keyword.

If you want the class to be managed, you should specify the __gc keyword.

Type the keyword struct or class as the type of object you are creating. That's the structOrClass factor in our syntax.

Specify the name of the class as the NewClass factor.

The colon (:) is read “is based on”. It lets the compiler know that the new object gets its foundation from another object. This operator is required.

The word AccessLevel specifies whether the object will use the public or private (or protected (coming soon)) level of access. The most common inheritance, which is also the most or only one we will use, is the public inheritance. If you are creating a class whose parent is a structure, you can omit this access level because a structure is public by default. Otherwise, you should specify the type of access.

The ParentClass is the name of the class that the new one is based on or is inheriting from.

When inheriting from another class, the new class is considered a child. It has access to the member variables of the public section(s) of the parent object. The inheriting object will not have access to the private members of the parent.

As an example, we can create a CBox class based on the CRectangle class we created earlier:

As we now have a working rectangle, we can use it as the base of a box. The header file of a CBox class creates an object whose base is the CRectangle object. Box
Header File: Box.h
#pragma once
#include ".\rectangle.h"

public __gc class CBox : public CRectangle
{
private:
	double width;
public:
	CBox();
	CBox(double L, double H, double W);
	void setDimensions(double L, double H, double W);
	double TotalArea(void);
	double Volume(void);

public:
	__property void set_Width(double w);
	__property double get_Width(void);

The source file is used to define the class. It makes sure that the new object has access to the desired properties of the parent. This is done using the access methods of the parent class called from the new constructors:

Source File: Box.cpp
#include "StdAfx.h"
#include ".\box.h"
#using <mscorlib.dll>

CBox::CBox(void)
	: CRectangle(0.00, 0.00), width(0.00)
{
}

CBox::CBox(double L, double H, double W)
	: CRectangle(L, H), width(0.00)
{
}

void CBox::setDimensions(double L, double H, double W)
{
	set_Length(L);
	set_Height(H);
	set_Width(W);
}

void CBox::set_Width(double w)
{
	width = (w < 0) ? 0 : w;
}

double CBox::get_Width(void)
{
	return width;
}

double CBox::TotalArea(void)
{
	double face1 = Length + Height;
    	double face2 = Height + Width;
    	double face3 = Length + Width;

    	return (2 * face1) + (2 * face2) + (2 * face3);
}

double CBox::Volume(void)
{
	return Length * Height * Width;
}

To test the new class, we will use the _tmain() function:

// This is the main project file for VC++ application project 
// generated using an Application Wizard.

#include "stdafx.h"
#include ".\rectangle.h"
#include ".\box.h"

#using <mscorlib.dll>

using namespace System;

void ShowCharacteristics(CRectangle*);
void ShowCharacteristics(CBox*);

int _tmain()
{
    // TODO: Please replace the sample code below with your own.
    CRectangle *rect = new CRectangle;
    CBox *grayBox = new CBox;

    rect->setDimensions(25.55, 20.82);
    grayBox->setDimensions(6.55, 5.25, 5.75);

    ShowCharacteristics(rect);
    ShowCharacteristics(grayBox);

    Console::WriteLine(S"");
    return 0;
}

void ShowCharacteristics(CRectangle* R)
{
    Console::WriteLine(S"Rectangle Characteristics");
    Console::WriteLine(S"Length:    {0}", __box(R->Length));
    Console::WriteLine(S"Height:    {0}", __box(R->Height));
    Console::WriteLine(S"Perimeter: {0}", __box(R->Perimeter()));
    Console::WriteLine(S"Area:      {0}", __box(R->Area()));
}

void ShowCharacteristics(CBox* B)
{
    Console::WriteLine(S"\nCharacteristics of the box");
    Console::WriteLine(S"Length:    {0}", __box(B->Length));
    Console::WriteLine(S"Height:    {0}", __box(B->Height));
    Console::WriteLine(S"Width:     {0}", __box(B->Width));
    Console::WriteLine(S"Area:      {0}", __box(B->TotalArea()));
    Console::WriteLine(S"Volume:    {0}", __box(B->Volume()));
}

This would produce:

Rectangle Characteristics
Length:    25.55
Height:    20.82
Perimeter: 92.74
Area:      531.951

Characteristics of the box
Length:    6.55
Height:    5.25
Width:     5.75
Area:      70.2
Volume:    197.728125

Press any key to continue
 

The protected Access Level

In the past, we learned that the public level allows the client of a class to access any member of a public section of a class. We also learned to hide other members by declaring them in the private section, which prevents the clients of the class from accessing such variables. You can create a special access level that allows only the children or derived objects of a class to have access to certain members of the parent class. This new access level is called protected. Therefore, to create a protected section in a class, type the protected keyword followed by a colon. Anything after that keyword until another access level will abide by the rules of a protected variable or method.

To allow the children of our CRectangle class to have a special permission in accessing some members of the parent class while the clients of CRectangle don't access those particular members, we can place those members in a protected section as follows:

Header File: Rectangle.h
#pragma once

public __gc class CRectangle
{
protected:
	double length;
	double height;
public:
	CRectangle(void);
	CRectangle(double L, double H);
    	void   setDimensions(double L, double H);
    	double Perimeter();
	double Area();
	
public:
	__property void   set_Length(double L);
   	__property double get_Length();	
	__property void   set_Height(double H);
	__property double get_Height();
};

Since only the access level of the member variables has changed, nothing needs to be done in the implementation of the CRectangle class. On the other hand, by making the member variables of the CRectangle class protected, the CBox class and its public members now have access to their parent’s protected members. This allows us the change the source file of the CBox object as follows:

Source File: Box.cpp
#include "StdAfx.h"
#include ".\box.h"
#using <mscorlib.dll>

CBox::CBox(void)
	: CRectangle(0.00, 0.00), width(0.00)
{
}

CBox::CBox(double L, double H, double W)
	: CRectangle(L, H), width(0.00)
{
}

void CBox::setDimensions(double L, double H, double W)
{
	length = L;
	height = H;
	width  = W;
}

void CBox::set_Width(double w)
{
	width = (w < 0) ? 0 : w;
}

double CBox::get_Width(void)
{
	return width;
}

double CBox::TotalArea(void)
{
    	double face1 = length + height;
    	double face2 = height + width;
    	double face3 = length + width;

    	return (2 * face1) + (2 * face2) + (2 * face3);
}

double CBox::Volume(void)
{
	return length * height * width;
}

As you can see, the derived class now has access to the protected member variables of the parent class and can use them to safely perform the needed calculations.

 

Inheritance-Related Issues

 

Class Nesting

A class can be created inside of another class. This means that a class can be nested in another's body. To do this, the nested class can be created as it would be outside. Suppose you create a class as follows:

Header File: test.h
#pragma once

__gc class CInside
{
public:
    CInside(void);
};

You can make such a class nested in another class. At the current standards of C++ and Managed C++, nesting a class in another class does not grant special access privileges to the nesting or parent class. Just because a class is nested does not mean that the nested class has immediate access to the members of the nesting class. Normally, this feature is supposed to change in the next standard of the languages. As of now, you must still declare a variable of the nested class in the nesting class. Here is an example:

Header File: test.h
#pragma once

using namespace System;

public __gc class COutside
{
public:
    __gc class CInside
    {
    public:
	CInside(void);
    };

public:
    CInside *item;
    COutside(void);
};

In the same way, you can nest as many classes as you wish in another class and you can nest as many classes inside of other nested classes if you judge it necessary.

To implement a method of a nested class, you can do so inline, that is, in the body of the class. If you want to implement a method of a nested class outside of the class, you must qualify it completely. Here is an example:

Source File: test.h
#include "StdAfx.h"
#include ".\test.h"
#using <mscorlib.dll>

COutside::COutside(void)
{
	Console::WriteLine(S" - The Parent Class -");
}

COutside::CInside::CInside(void)
{
	Console::WriteLine(S" - The Child Class -");
}

To declare a variable of a nested class, you must qualify it, once again, to let the compiler know where the class was created. Here is an example:

// This is the main project file for VC++ application project 
// generated using an Application Wizard.

#include "stdafx.h"
#include ".\test.h"

#using <mscorlib.dll>

using namespace System;

int _tmain()
{
    // TODO: Please replace the sample code below with your own.
    COutside *parent = new COutside;
    COutside::CInside *ins = new COutside::CInside;

    Console::WriteLine(S"");
    return 0;
}

This would produce:

- The Parent Class -
- The Child Class -

Press any key to continue
 

Namespaces and Inheritance

Class inheritance that involves namespaces relies on qualification, like the calling of the members of a namespace. To derive a class from a class member of a namespace, type the name of the namespace, followed by the access operator "::", and followed by the name of the base namespace. For example, imagine you had created the CRectangle object as follows:

Header File: Rectangle.h
#pragma once

namespace FlatShapes
{
public __gc class CRectangle
{
protected:
	double length;
	double height;
public:
	CRectangle(void);
	CRectangle(double L, double H);
    	void   setDimensions(double L, double H);
    	double Perimeter();
	double Area();
	
public:
	__property void   set_Length(double L);
   	__property double get_Length();	
	__property void   set_Height(double H);
	__property double get_Height();
};
}

To inherit from this class, the compiler will need to know the namespace in which CRectangle was created. Therefore, you can inherit a CBox object as follows:

Header File: Box.h
#pragma once
#include ".\rectangle.h"

namespace Volumes
{
public __gc class CBox : public FlatShapes::CRectangle
{
protected:
	double width;
public:
	CBox();
	CBox(double L, double H, double W);
    	void setDimensions(double L, double H, double W);
	double TotalArea(void);
	double Volume(void);

public:
	__property void set_Width(double w);
	__property double get_Width(void);
};
}

If you need to call the class that was defined in a different namespace, remember to qualify its name with the scope access operator. Here is an example:

#include "Box.h"

namespace Volumes
{
CBox::CBox(double L, double H, double W)
    : FlatShapes::CRectangle(L, H), FWidth(W)
{
}
}

Alternatively, as mentioned in the past, to use the contents of a namespace, prior to calling a member of that namespace, you can type using namespace followed by the name of the namespace.

 

Multiple Inheritance

The most common inheritance consists of a class deriving its foundation from another class. This is referred to as single inheritance. C++ allows a class to be based on more than one class. This is referred to as multiple inheritance.

Multiple Inheritance

When a class is based on many other classes, it benefits from the member variables and methods of those classes. It has direct access to the public and protected members of each parent class.

To apply a multiple inheritance, specify each class on the right side of the : operator. Here is an example:

#pragma once

#include <iostream.h>
#include "Person.h"
#include "Address.h"

class CStaff : public CPerson, public CAddress
{
public:
    CStaff();
    CStaff(string fn, string ln,
    string a, string c, string s, string z,
    double L, char e, int m);
    CStaff(const CStaff& S);
    ~CStaff();
    void setSalary(const double s) { Salary = s; }
    double getSalary() const;
    void setEmplStatus(const char e) { EmploymentStatus = e; }
    string getEmploymentStatus() const;
    void setMaritalStatus(const int m) { MaritalStatus = m; }
    string getMaritalStatus() const;
protected:
    double Salary;
    char EmploymentStatus;
    int MaritalStatus;
};

#endif

In most cases you should avoid multiple inheritance. As an example, Managed C++ supports multiple inheritance only in the issue of interface that we will learn soon.

 

 


Previous Copyright © 2004 FunctionX, Inc. Next