Inheritance and stuff

Use of constructors

Here is a neat way to trace the execution of your program.
class Trace {
	public:
		Trace(char *);
		~Trace();
	private:
		char * fn;
} // Trace

Trace::Trace(char * mesg)
{
	cerr << "now entering: " << mesg << endl;
	fn = strdup(mesg);
} // trace constructor

Trace :: ~Trace()
{
	cerr << "now leaving: " << fn << endl;
	free(fn);
} // trace destructor

Now in any function you want to trace:

int
foo(int a,int b)
{
	Trace tracer("foo");
	other stuff
} // foo

The constructor is called at the beginning of the function and the destructor at the end. This can be expanded to use a file member to record tracing, read an environment variable to see if tracing is on, keep a list of functions to be traced and only trace those, etc.

Inheritance

There are two methods for building classes from other classes in C++. We can construct a class using existing classes. This is called composition. This expresses the has-a relationship. For example:
class Publisher {
	public:
		// various interface methods
	private:
		char * name;
		char * url;
};

class Book {
	public:
		// various interface routines
	private:
		int a;
		Publisher p;
};

Book has-a Publisher;

Inheritance expresses the is-a relationship.

Inheritance allows us to abstract some parts of the data to hide them from the programmer, while allowing re-use of other parts. For example, a product consists of one or more programs. Programs consist of one or more code units.

Products have data like release dates, cost, part numbers, manuals, owner, completion date, etc. They have methods like is_development_complete() and get_part_number();

Programs have owners, language, compiler, completion date. They have methods like is_development_complete() and compile_program();

Code units have owners, language compilers, unit test date, completion date, NCSL. They have methods like is_development_complete() and compile_program() and count_ncsl().

You can see that there are commonalities and differences.

#include 
#include 
#include 
using namespace std;
The foo class is much like the one we saw before except that the 
title element and some methods have been removed.

class foo {
	public: // first we do all the public interface methods
		// these are used to put values in the private data elements
		void set_a(int x) { a=x;}
		void set_b(int x) { b=x;}

		// these are used to get the values from the private data elements
		int get_a() { return(a);}
		int get_b() { return(b);}

		// these are the constructors
		foo() { a = 0; b = 0;} // default constructor
		foo(int x) { a=x; b = 0;}
		foo(int x,int y) { a= x; b = y;}

	private: // these are private data, not visible outside the class
		int a,b;
}; // class foo

// class bar inherits from foo, so we only need to specify the things
// that are unique to bar
class bar : public foo {
Using public before foo means that we want the private elements 
to be included in bar. Marking it private would mean we only get the 
public data. Almost always you will want to mark it public. 
foo is known as the superclass or the base class for 
bar and bar is known as the derived or subclass.
	public:
		void set_c(int x) { c=x;}
		int get_c() { return(c);}

		// these are the constructors
		bar() {c = 0;}
		bar(int x) {c=x;}
		// a and b, although inherited by bar, are still private to foo
		bar(int x,int y, int z) { set_a(x); set_b(y); c = z;}
	private:
		int c;
}; // class bar

int
main(int argc, char **argv)
{
	foo X,Y(6),Z(7,8);
	bar A,B(9),C(1,2,3);

	printf("X.a = %d X.b = %d\n",X.get_a(),X.get_b());
	printf("Y.a = %d Y.b = %d\n",Y.get_a(),Y.get_b());
	printf("Z.a = %d Z.b = %d\n",Z.get_a(),Z.get_b());

	printf("A.a = %d A.b = %d A.c = %d\n",A.get_a(),A.get_b(),A.get_c());
	printf("B.a = %d B.b = %d B.c = %d\n",B.get_a(),B.get_b(),B.get_c());
	printf("C.a = %d C.b = %d C.c = %d\n",C.get_a(),C.get_b(),C.get_c());
	/* here is what I get when I run this with g++
	X.a = 0 X.b = 0
	Y.a = 6 Y.b = 0
	Z.a = 7 Z.b = 8
	A.a = 0 A.b = 0 A.c = 0
	B.a = 0 B.b = 0 B.c = 9
	C.a = 1 C.b = 2 C.c = 3
	*/

	/* the following statements are illegal
 	remove the comment markers and see what your compiler does
 	with them
	*/
	// cout << X.get_c() << endl;
	// cout << A.c << endl;

	/* here are the errors I get
		inh.cc: In function `int main(int, char **)':
		inh.cc:67: no matching function for call to `foo::get_c ()'
		inh.cc:68: member `c' is a private member of class `bar'
	*/
} // main

Note the public before bar. C++ defaults to private access to the superclass, which means we don't have access to the private members of the superclass. there are two kinds of inheritance access.

  private public
private private private
protected private protected
public private public

protected members are private to outside classes but public to subclasses. So if we had put a and b in foo in the protected section, then bar would have been able to refer to them directly, as if they were really part of the class.

Constructors

The constructors for the superclasses are called before the constructor for the class is called. This is so all inherited values are initialized as needed before the subclass variables are set. In the class above, when we call
bar(1,2,3);
before the 3 arg constructor is executed, the no arg constructor for foo is run. Then the calls to set_a() and set_b() override the initialization. This is a little redundant. So we can define the subclass constructor to use the parameterized superclass constructor.
foo(const int X,const int Y, const int Z) : foo(X,Y)
{
	c=Z;
}

If there were more superclasses, make a comma separated list. This can be used to initialize variables by calling a constructor.

point() : x(0),y(0) {};
point( const int X,const int Y) : x(x),y(y) {};

Overriding the base class

If the derived class has a method or data element with the same name as the base class, the thing in the derived class takes precedence. Lets look at a new version of bar that has a method with the same name as one in foo. The base code is here. This is a very important feature of C++ and object oriented programming. Each of the classes has its own version of bigger() that is approriate to it. The user only has to know that they should call bigger() on an instance and they will get the right value.
#include 
#include 
#include 
using namespace std;

class foo {
    public:    // first we do all  the public interface methods
    // these are used to put values in the private data elements
    void set_a(int x) { a=x;}
    void set_b(int x) { b=x;}

    // these are used to get the values from the private data elements
    int get_a() { return(a);}
    int get_b() { return(b);}
    int bigger(); 

    // these are the constructors
    foo() { a = 0; b = 0;}   // default constructor
    foo(int x) { a=x; b = 0;}
    foo(int x,int y) { a= x; b = y;}

    private:  // these are private data, not visible outside the class
    int a,b;
}; // class foo

int
foo::bigger()
{
   if(a < b) return(b);
   return(a);
} // foo::bigger

// class bar inherits from foo, so we only need to specify the things
// that are unique to bar
class bar : public foo {
   public:
    void set_c(int x) { c=x;}
    int get_c() { return(c);}
    int bigger(); // same name as one in foo

    // these are the constructors
    bar() {c = 0;}
    bar(int x) {c=x;}
    // a and b, although inherited by bar, are still private to foo
    bar(int x,int y, int z) { set_a(x); set_b(y); c = z;}
   private:
   int c;
}; // class bar

int
bar::bigger()
{
   if(get_a() < c) return(c);
   return(get_a());
} // bar::bigger

int 
main(int argc, char **argv)
{
   foo X,Y(6),Z(7,8);
   bar A,B(9),C(1,2,3);

   printf("X.a = %d X.b = %d\n",X.get_a(),X.get_b());
   printf("Y.a = %d Y.b = %d\n",Y.get_a(),Y.get_b());
   printf("Z.a = %d Z.b = %d\n",Z.get_a(),Z.get_b());

   printf("A.a = %d A.b = %d A.c = %d\n",A.get_a(),A.get_b(),A.get_c());
   printf("B.a = %d B.b = %d B.c = %d\n",B.get_a(),B.get_b(),B.get_c());
   printf("C.a = %d C.b = %d C.c = %d\n",C.get_a(),C.get_b(),C.get_c());

// now lets play with bigger()
   printf("C.bigger = %d \n",C.bigger());
   printf("Z.bigger = %d \n",Z.bigger());
   printf("C.foo::bigger = %d \n",C.foo::bigger());


/* here is what I get when I run this with g++
X.a = 0 X.b = 0
Y.a = 6 Y.b = 0
Z.a = 7 Z.b = 8
A.a = 0 A.b = 0 A.c = 0
B.a = 0 B.b = 0 B.c = 9
C.a = 1 C.b = 2 C.c = 3
C.bigger = 3
Z.bigger = 8
C.foo::bigger = 2
*/
 
} // main