Matrices Introducing Inheritance Calvin College Consider A matrix

  • Slides: 48
Download presentation
Matrices Introducing Inheritance Calvin College

Matrices Introducing Inheritance Calvin College

Consider A matrix is a grid in which numbers can be stored. 1 9

Consider A matrix is a grid in which numbers can be stored. 1 9 2 8 3 7 4 6 5 Algorithms for problems in scientific computing frequently store the coefficients for a system of equations in a matrix, for convenient manipulation. A class to represent matrices is thus a useful class for scientific computing. Calvin College

Problem Let’s write a program to perform matrix addition. 1 9 2 8 3

Problem Let’s write a program to perform matrix addition. 1 9 2 8 3 7 4 6 5 m 1 + 1 2 3 4 5 6 7 8 9 m 2 ® 2 11 5 12 8 13 11 14 10 m 3 For simplicity, we will store a matrix’s values in a file. Since there is no predefined Matrix type, we will design a Matrix class. . . Calvin College

Behavior Our program should explain its purpose, and prompt for and read the values

Behavior Our program should explain its purpose, and prompt for and read the values of the first matrix from the keyboard. It should then do the same for the second matrix. It should then add the two matrices producing a third matrix. It should then display the third matrix to the screen. Calvin College

Objects Description Type 1 st matrix keyboard 2 cd matrix 3 rd matrix screen

Objects Description Type 1 st matrix keyboard 2 cd matrix 3 rd matrix screen Matrix istream Matrix ostream Calvin College Kind varying varying Name matrix 1 cin matrix 2 matrix 3 cout

Operations Description Predefined? Library? Name display a string yes string << read a matrix

Operations Description Predefined? Library? Name display a string yes string << read a matrix from istream no --- >> add 2 matrices no --- ? ? ? write a matrix to ostream no --- ? ? ? Calvin College

Algorithm 0. Display purpose of program 1. Prompt for and read matrix 1 using

Algorithm 0. Display purpose of program 1. Prompt for and read matrix 1 using cin. 2. Prompt for and read matrix 2 using cin. 3. Compute matrix 3 = matrix 1 + matrix 2. 4. Write matrix 3 to cout. Calvin College

Coding Our Algorithm Ideally, we want to implement our algorithm this way: // mat.

Coding Our Algorithm Ideally, we want to implement our algorithm this way: // mat. Add. cpp //. . . documentation //. . . other #includes #include “Matrix. h” int main() { cout << “n. To add two matrices, enter the” << “n values of the first matrix“ << “n (one row per line)n”; Matrix mat 1; cin >> mat 1; cout << “n. Do the same for the second matrix: n”; Matrix mat 2; cin >> mat 2; // Calvin. . . College

Coding (Ct’d) //. . . mat. Add. cpp continued Matrix mat 3 = mat

Coding (Ct’d) //. . . mat. Add. cpp continued Matrix mat 3 = mat 1 + mat 2; } cout << << “n. The sum ofn” mat 1 << “nn andnn” mat 2 << “nn isnn” mat 3 << “nn”; If we build an easy-to-use Matrix class, writing a program to manipulate matrices can be as easy as writing a program that manipulates integers. Calvin College

Analysis We have a few function members to define! Our algorithms requires: – matrix

Analysis We have a few function members to define! Our algorithms requires: – matrix input from an istream – matrix addition – matrix output to an ostream In addition, we should provide “normal” class operations (normal constructors, accessors) as well as other Matrix operations. Calvin College

Difficulty We could declare our Matrix class as follows: class Matrix { public: //.

Difficulty We could declare our Matrix class as follows: class Matrix { public: //. . . private: int my. Rows, my. Columns; typedef vector<double> Row; vector<Row> my. Grid; }; However, if we do so, then we must redefine many of the vector operations for our Matrix class, which will greatly increase our development time. Calvin College

For Example If we take this approach, then we will be unable to use

For Example If we take this approach, then we will be unable to use the subscript operator on a Matrix object: Matrix mat 1; //. . . cout << mat 1[0][0] << endl; The reason is that a Matrix declared using this approach has-a vector of vectors as a data member, but such Matrix is not a vector of vectors. That is, although subscript is an operation defined for class vector, it is not defined for a Matrix unless we define it (as is the case for all vector operations). Calvin College

A Solution One way to avoid this problem is to declare our Matrix class

A Solution One way to avoid this problem is to declare our Matrix class as an extension to vector of vectors: typedef vector<double> Row; class Matrix : public vector<Row> { //. . . }; This approach tells the compiler that a Matrix a vector<double> >. Since such a Matrix is a vector<Row>, any operation that can be applied to vector<Row> can Calvin be College applied to a Matrix (including subscript)! is

Example With this definition (and a constructor we’ll write shortly), we can write: Matrix

Example With this definition (and a constructor we’ll write shortly), we can write: Matrix mat 1(2, 3); cin >> mat 1[0][0]; mat 1 [0] [1] [2] [0] [1] inherited data member(s) Calvin College

Example With this definition (and a constructor we’ll write shortly), we can write: Matrix

Example With this definition (and a constructor we’ll write shortly), we can write: Matrix mat 1(2, 3); cin >> mat 1[0][0]; mat 1 [0] [1] [2] [0] [1] inherited data member(s) The first subscript selects the Row whose index is 0 within mat 1. Calvin College

Example With this definition (and a constructor we’ll write shortly), we can write: Matrix

Example With this definition (and a constructor we’ll write shortly), we can write: Matrix mat 1(2, 3); cin >> mat 1[0][0]; mat 1 [0] [1] [2] [0] [1] inherited data member(s) The first subscript selects the Row whose index is 0 within mat 1. The second subscript selects the column whose index is 0 with in that Row. Calvin College

Inheritance In such a declaration, Matrix is said to be derived from vector<Row>. The

Inheritance In such a declaration, Matrix is said to be derived from vector<Row>. The Matrix class is said to inherit all of the members (data and function) of vector<Row>. The pattern for such a declaration is as follows: class Child. Class : public Parent. Class { //. . . }; Child. Class is derived from Parent. Class, and inherits all of. Calvin its College members, both function and data.

Inheritance (Ct’d) Parent Class The is-a relationship is often drawn like this: A parent

Inheritance (Ct’d) Parent Class The is-a relationship is often drawn like this: A parent class can have many derived classes, which are sometimes called child classes: Calvin College Derived Class Parent Class. . . Child 1 Child 2 Child. N

Inheritance (Ct’d) Parent Class Child classes can also be parents, producing class hierarchies: .

Inheritance (Ct’d) Parent Class Child classes can also be parents, producing class hierarchies: . . . Child 1 GChild 1 Child 2 GChild 2 Such hierarchies are useful for modeling relationships among real world objects. Child. N GChild 3 Vehicle Car compact sedan. . . Truck . . . wagon. . . By consolidating common code in parent classes, inheritance can eliminate Calvin College all redundant code. Boat . . .

Using Inheritance can be used to declare any class that is a special instance

Using Inheritance can be used to declare any class that is a special instance of another class. Since the derived class inherits all members of the parent class, inheritance should only be used if every operation on the parent class can be appropriately applied to the derived class Calvin College

Declaring Matrix We can thus start a Matrix class as follows: typedef vector<double> Row;

Declaring Matrix We can thus start a Matrix class as follows: typedef vector<double> Row; class Matrix : public vector<Row> { public: private: int my. Rows, my. Columns; }; No my. Grid data member is needed, because Matrix inherits the implementation details of vector<Row>. The data members my. Rows and my. Columns are not required, but they simplify some operations. Calvin College

The Matrix Interface class Matrix : public vector<Row> { public: Matrix(); Matrix(int rows, int

The Matrix Interface class Matrix : public vector<Row> { public: Matrix(); Matrix(int rows, int columns); int Rows() const; int Columns() const; Matrix operator+(const Matrix & mat 2) const; //. . . other Matrix-specific operations void Read(istream & in); void Print(ostream & out) const; friend istream & operator>>(istream & in, Matrix & chart); friend ostream & operator<<(ostream & in, const Matrix & chart); private: //. . . data members omitted }; Calvin College

Default Constructor The default constructor initializes the data members to default values: Matrix mat

Default Constructor The default constructor initializes the data members to default values: Matrix mat 1; Specification: Postcondition: my. Rows == 0 && my. Columns == 0. We should use the vector<Row> constructor to initialize the inherited data members. . . Calvin College

Default Constructor This is sufficiently simple to define inline in Student. h: inline Matrix:

Default Constructor This is sufficiently simple to define inline in Student. h: inline Matrix: : Matrix() : vector<Row>() { my. Rows = 0; my. Columns = 0; } Calvin College

Default Constructor This is sufficiently simple to define inline in Student. h: inline Matrix:

Default Constructor This is sufficiently simple to define inline in Student. h: inline Matrix: : Matrix() : vector<Row>() { my. Rows = 0; my. Columns = 0; } The notation : vector<Row>() calls the constructor for class vector<Row> (Matrix’s parent class). A derived class constructor can (and should) always use this pattern to call the constructor of its parent class, to initialize its inherited data members. Calvin College

Explicit-Value Constructor This constructor lets you construct a Matrix of a specified size (in

Explicit-Value Constructor This constructor lets you construct a Matrix of a specified size (in rows and columns): Matrix mat 1(3, 5); mat 1 The inherited data are wrapped in orange. Specification: ? ? ? [0] [1] [2] [3] [4] [0] 0 0 0 [1] 0 0 0 [2] 0 0 0 my. Rows my. Columns 3 5 Receive: rows, columns, two int values. Precondition: rows > 0 && columns > 0. Postcondition: my. Rows == rows && my. Columns == columns && I contain a 2 -D vector of rows and columns. Calvin College

Explicit-Value Constructor This is sufficiently simple to define inline: inline Matrix: : Matrix(int rows,

Explicit-Value Constructor This is sufficiently simple to define inline: inline Matrix: : Matrix(int rows, int columns) : vector<Row>(rows, Row(columns)) { assert(rows > 0 && columns > 0); my. Rows = rows; my. Columns = columns; } Calvin College

Explicit-Value Constructor This is sufficiently simple to define inline: inline Matrix: : Matrix(int rows,

Explicit-Value Constructor This is sufficiently simple to define inline: inline Matrix: : Matrix(int rows, int columns) : vector<Row>(rows, Row(columns)) { assert(rows > 0 && columns > 0); my. Rows = rows; my. Columns = columns; } The : vector<Row>(rows, Row(columns)) calls vector<Row>() to initialize the inherited members. This constructor lets the caller specify the size (rows ), and ( the initial value (Row(columns) ) of the vector. ( The Row constructor (i. e. , vector<double>) is used to Calvin initial College define the value as a vector of size columns.

Extractors The extractors retrieve data member values: cout << mat 1. Rows() << mat

Extractors The extractors retrieve data member values: cout << mat 1. Rows() << mat 1. Columns(); Specifications: Rows(): Columns(): Calvin College Return my. Rows. Return my. Columns.

Extractors These are sufficiently simple to define inline: inline int Matrix: : Rows() const

Extractors These are sufficiently simple to define inline: inline int Matrix: : Rows() const { return my. Rows; } inline int Matrix: : Columns() const { return my. Columns; } Calvin College

Element Access Thanks to our having derived Matrix from vector<Row>, we can write: cout

Element Access Thanks to our having derived Matrix from vector<Row>, we can write: cout << mat 1[r][c]; and access the element at row r, column c, using the inherited subscript operators. Calvin College

Element Access Thanks to our having derived Matrix from vector<Row>, we can write: cout

Element Access Thanks to our having derived Matrix from vector<Row>, we can write: cout << mat 1[r][c]; and access the element at row r, column c, using the inherited subscript operators. Since mat 1 is a vector<Row>, sending mat 1 the subscript message [r] accesses the Row in mat 1 whose index is r. Calvin College

Element Access Thanks to our having derived Matrix from vector<Row>, we can write: cout

Element Access Thanks to our having derived Matrix from vector<Row>, we can write: cout << mat 1[r][c]; and access the element at row r, column c, using the inherited subscript operators. Since mat 1 is a vector<Row>, sending mat 1 the subscript message [r] accesses the Row in mat 1 whose index is r. We then send that Row the subscript message [c], which accesses the column within that Row whose index is c. Calvin College

Print() This member lets you write a matrix to an ostream: mat 1. Print(cout);

Print() This member lets you write a matrix to an ostream: mat 1. Print(cout); Specification: Receive: out, an ostream. Output: my (Matrix) values, to out. Passback: out, containing my Matrix values; Calvin College

Defining Print() This is sufficiently complicated to define separately. //. . . void Matrix:

Defining Print() This is sufficiently complicated to define separately. //. . . void Matrix: : Print(ostream & out) const { for (int r = 0; r < Rows(); r++) for (int c = 0; c < Columns(); c++) { fout << (*this)[r][c]; if (c < Columns()-1) out << ‘t’; else out << ‘n’; } } Calvin College // for each r // for each c // display // either // tab // or // newline

this The tricky thing here is that within a function member, we must send

this The tricky thing here is that within a function member, we must send ourselves the subscript message. Every C++ function member has a variable named this. When that member’s message is sent to an object, the address of the receiving object is stored in this. mat 1. Print(cin); this Matrix: : Print() Calvin College mat 1

this (Ct’d) In a C++ function member, this always contains the address of the

this (Ct’d) In a C++ function member, this always contains the address of the object receiving the message. Since it stores an address, this can be thought of as pointing to the object receiving the message, and address-storing variables are commonly called pointers. Since the value of this is an address, we can’t use it as is to refer to the receiver of the message. Calvin College

this (Ct’d) When applied to a pointer as a prefix operator, the asterisk (*

this (Ct’d) When applied to a pointer as a prefix operator, the asterisk (* ( ) produces as its value the object pointed to. That is, if we use the notation: (*this) within a function member, the effect will be to access the receiver of the message (i. e. , ourselves). To send ourselves the subscript message, we thus write: (*this)[r][c] which selects the Row whose index is r within ourselves (and then sends that Row a second subscript message). Calvin College

Insertion Overloading the insertion operator will let us display a Matrix in the “normal”

Insertion Overloading the insertion operator will let us display a Matrix in the “normal” manner: cout << mat << endl; Since its left operand is an ostream, this function cannot be implemented as a function member. Specification: Receive: out, an ostream; mat, a Matrix. Output: the values in mat, via out. Passback: out, containing the Matrix. Return: out, for chaining. Calvin College

Defining Insertion Thanks to Print(), this is sufficiently simple to inline. //. . .

Defining Insertion Thanks to Print(), this is sufficiently simple to inline. //. . . inline ostream & operator<<(ostream & out, const Matrix & mat) { mat. Print(out); // send mat the Print() msg return out; // allow chaining } We simply send our Matrix parameter the Print() message, and let it do the work. . . Calvin College

Read() This member lets you read a matrix via an istream: mat 1. Read(cin);

Read() This member lets you read a matrix via an istream: mat 1. Read(cin); Specification: Receive: in, an istream. Precondition: in contains the values of an m-by-n matrix, with each row on a separate line. Input: the matrix values, via in. Passback: in, the matrix values extracted from it. Postcondition: I contain the input values. Calvin College

Defining Read() This is sufficiently complicated to define separately. //. . . void Matrix:

Defining Read() This is sufficiently complicated to define separately. //. . . void Matrix: : Read(istream & in) { double number; char separator; for (; ; ) // row-loop { Row a. Row; // empty row for (; ; ) // column-loop { in >> number; // read number if (in. eof()) break; // quit if failed a. Row. push_back(number); // append number in. get(separator); // read next char if (separator == ‘n’) break; // quit if e-o-l } // end column-loop if (in. eof()) break; // quit if eof push_back(a. Row); // append Row } // end row-loop Calvin College }

Extraction The extraction operator lets us read a Matrix from an istream, like any

Extraction The extraction operator lets us read a Matrix from an istream, like any other object: cin >> mat 1; Specification: Receive: in, an istream; mat, a Matrix. Precondition: my. Rows == m && my. Columns == n && in contains the values of an m-by-n matrix, with one row/line. Input: the matrix, via in. Passback: in, the matrix read from it; mat, containing the extracted values. Return: in, for chaining. Calvin College

Defining Extraction Thanks to Read(), this is simple enough to inline: //. . .

Defining Extraction Thanks to Read(), this is simple enough to inline: //. . . inline istream & operator>>(istream & in, Matrix & mat) { mat. Read(in); return in; } We simply send our Matrix parameter the Read() message, and let it do the work. . . Calvin College

Matrix Addition Defining the + operator will let us add matrices: Matrix mat 3

Matrix Addition Defining the + operator will let us add matrices: Matrix mat 3 = mat 1 + mat 2; Since its left operand is a Matrix, we can define operator+ as a Matrix function member, in which case such an expression will be treated as: Matrix mat 3 = mat 1. operator+(mat 2); Specification: Receive: mat 2, a Matrix. Precondition: mat 2. Rows() == my. Rows && mat 2. Columns() == my. Columns. Calvin College Return: mat 3, containing the sum of myself and mat 2.

Addition Operator This is sufficiently complicated to define separately. //. . . Matrix: :

Addition Operator This is sufficiently complicated to define separately. //. . . Matrix: : operator+(const Matrix & mat 2) const { assert(mat 2. Rows() == my. Rows && mat 2. Columns() == my. Columns); Matrix result(my. Rows, my. Columns); for (int r = 0; r < my. Rows; r++) for (int c = 0; c < my. Columns; c++) result[r][c] = (*this)[r][c] + mat 2[r][c]; } return result; Since the problem requires that we access all of the values in a 2 -D structure, we use two nested for loops. Calvin College

Our Program Our program will now work “as advertised”. //. . . int main()

Our Program Our program will now work “as advertised”. //. . . int main() { //. . . cin >> mat 1; //. . . cin >> mat 2; //. . . Matrix mat 3 = mat 1 + mat 2; //. . . cout << mat 3; //. . . } All of our work is reuseable, and we can add more matrix -specific operations to class Matrix. . . Calvin College

Summary If a new class is a special instance of an existing class, derivation

Summary If a new class is a special instance of an existing class, derivation can be used to define the new class. A derived class inherits all members (except constructors and destructors) of its parent class. A derived class constructor should use the parent class constructor to initialize inherited data members. In function members, this is built-in variable containing the address of the receiver of the message. Within a function member, the expression (*this) refers to the object receiving the message. Calvin College