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.
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.
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) {};
#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