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.
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 <stdio.h> #include <stream.h> #include <stdlib.h> #include <string.h> 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' */ } // mainNote 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 |
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) {};
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
class instrument {
public:
void play(int
note) { cout << "instrument::play" << endl;}
}; // instrument
class wind : public instrument {
public:
void play(int
note) { cout << "wind::play" << endl;}
}; // wind
void tune(instrument& i)
{
i.play(1);
}
main()
{
wind flute;
tune(flute);
} // main
This prints instrument::play. This is because the variable in tune() is of type instrument so it uses the function from there, even though we passed in a flute. Change the definition in instrument to:
virtual void play(int note) { cout << "instrument::play" << endl;}
Now running the program prints wind::play. The function to be called is determined at run time (late binding). This technique allows us to write functions like tune() that will work for any derived class from a base class. It is easier to extend the classes because tune() still works for other classes derived from instrument. Like drum or guitar. It will also work for lower levels. If class brass is derived from wind, tune() still works. If there is no overridden functions, the one next up the hierarchy is used.