// ------------------------------------ // inherit.cpp // ------------------------------------ #include "w.h" /* This illustrates some ideas to do with derived classes, and dynamic memory allocation. We consider a matrix class mat and derived classes rvec and cvec, representing row and column vectors. The classes mat, rvec, and cvec each has its own distinct norm function. Try the program with 'virtual' in mat::norm() removed: in this form, the global function norm() always calls mat::norm(); we want exactly what happens with 'virtual' present, that is to say, the global norm() calls the correct D::norm() for each derived class D. NB Internal storage is in `array style' [0 1 .. n-1] Externally it is the`mathematics style' [1 2 .. n] */ class mat { public: mat(int mi, int ni); mat(int mi, int ni, const double ai[]); virtual ~mat(); inline int getm() { return m; } inline int getn() { return n; } inline double getel(int i, int j) {return a[n*(i-1) + j-1]; } virtual double norm(); // L1 norm protected: // may be accessed by derived classes int m,n; double *a; }; mat::mat(int mi, int ni): m(mi),n(ni) { a = new double[m*n]; } mat::mat(int mi, int ni, const double ai[]): m(mi),n(ni) { a = new double[m*n]; for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) a[i*n+j] = ai[i*n+j]; } mat::~mat() { if (a != NULL) {delete [] a; a = NULL;} } double mat::norm() { double sum = 0; for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) sum += fabs(a[i*n+j]); return sum; } // -------------------------------------------- // derived classes rvec and cvec [row and column vectors] class rvec : public mat { public: rvec(int n):mat(1,n) {} rvec(int n, double ai[]):mat(1,n,ai) {} ~rvec() { if (a != NULL) { delete [] a; a = NULL; }} double norm(); // L2 norm }; double rvec::norm() // L2 norm { double sum = 0; for (int i = 0; i < n; i++) sum += a[i]*a[i]; return sqrt(sum); } // --------------------------------- class cvec : public mat { public: cvec(int m):mat(m,1) {} cvec(int m, double ai[]):mat(m,1,ai) { } ~cvec() { if (a != NULL) { delete [] a; a = NULL; }} double norm(); // L4 norm }; double cvec::norm() // L4 norm { double sum = 0; for (int i = 0; i < m; i++) sum += pow(a[i],4); return pow(sum,0.25); } // ------------------------------------------------------------- // global print function designed for mat, // but also works for derived classes. void p(mat *ma) { int m = ma->getm(), n = ma->getn(); for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { p(ma->getel(i,j)); p(" "); } nl(); } } void pl(mat *ma) { p(ma); nl(); } // ------------------------------------------------------------- // global norm function designed for mat, // but returns the appropriate norm for each derived class. // This magic requires 'virtual' before mat::norm(). double norm(mat *ma) { return ma->norm(); } // ------------------------------------------------------------- void main() { nl(0); banner("inherit.cpp"); double a[] = {1,2,3,2,4,6}; mat *m1 = new mat(2,3,a); pl("m1 = "); pl(m1); pl("norm = ", norm(m1)); // mat::norm() nl(); rvec *rv = new rvec(5,a); pl("rv = "); pl(rv); pl("norm = ", norm(rv)); // rvec::norm() nl(2); cvec *cv = new cvec(3,a); pl("cv = "); pl(cv); pl("norm = ", norm(cv)); // cvec::norm() delete m1,rv,cv; } // ------------------------------------------------------ /* output ------------- inherit.cpp ------------- m1 = 1 2 3 2 4 6 norm = 18 rv = 1 2 3 2 4 norm = 5.83095 cv = 1 2 3 norm = 3.14635 */