If pointer p points to a structure or class object, access to a member of the structure or class object member through the pointer is (*p).member. The expression (*p).member and p->member have the same meaning.
In a member function definition the predefined this pointer variable is provided (implicitly) to every non-static member function. This pointer points to the calling object. Any member function or variable that may be used in the implementation of a member function has this-> implicitly prefixed. If the function is declared to be static, then this is not supplied, and direct access to non-static members is unavailable.
The assignment operator must be implemented as a member function. There are several operators whose overloaded operator functions must be implemented as non-static member functions. These are [], (), ->, and =.
If these continued assignments aren’t required, a void return type suffices.
Destructors
Copying is not quite intuitive in C++. C++ considers these three situations to be copying:
Based on code from Display 10.9, write a class TwoD that implements a two-dimensional dynamic array of double.
Notes: I overloaded the function call operator to serve as index. That way, matrix(i, j) returns the (i, j) element, while matrix(i) returns the ith row. (I did not implement this last overloading. I only supplied the declaration.)
#include
using std::exit;
using std::cin;
using std::cout;
using std::endl;
typedef double* DoubleArrayPtr;
class TwoD
{
public:
TwoD(); // sets maxRows and maxCols each to 10
TwoD(int maxR, int maxC);
~TwoD();
TwoD(const TwoD&);
const TwoD& operator=(const TwoD& rhs);
double& operator()(int r, int c); // returns row r, col c element
double* operator()(int r); //returns pointer to row r. Ordinary index
//extracts elements from this operator.
friend TwoD operator+(const TwoD& lhs, const TwoD& rhs);
friend int myRows(const TwoD&);
friend int myCols(const TwoD&);
private:
DoubleArrayPtr * matrix;
int maxRows;
int maxCols;
};
int main( )
{
int d1, d2, i, j;
cout << "Enter the row and column dimensions of the array\n";
cin >> d1 >> d2;
TwoD matrix1(d1, d2);
cout << "Enter " << d1 << " rows of "
<< d2 << " doubles each\n";
for (i = 0; i < d1; i++)
for (j = 0; j < d2; j++)
cin >> matrix1(i,j);
cout << "Echoing the 2 dim. array, matix1\n";
for (i = 0; i < d1; i++)
{
for (j = 0; j < d2; j++)
cout << matrix1(i,j) << " ";
cout << endl;
}
cout << "Enter the row and column dimensions of the array\n";
cin >> d1 >> d2;
TwoD matrix2(d1, d2), matrix3;
cout << "Enter " << d1 << " rows of "
<< d2 << " doubles each\n";
for (i = 0; i < d1; i++)
for (j = 0; j < d2; j++)
cin >> matrix2(i,j);
cout << "Echoing the 2 dim. array, matrix2\n";
for (i = 0; i < myRows(matrix2); i++)
{
for (j = 0; j < myCols(matrix2); j++)
cout << matrix2(i,j) << " ";
cout << endl;
}
cout << "assigning matrix 2 to matrix 3 " << endl;
matrix3 = matrix2;
cout << "Displaying the 2 dim array, matrix3 "
<< "resulting from assignmnet.\n";
cout << "rows " << myRows(matrix3) << " "
<< "cols " << myCols(matrix3) << endl;
for (i = 0; i < myRows(matrix3); i++)
{
for (j = 0; j < myCols(matrix3); j++)
cout << matrix3(i,j) << " ";
cout << endl;
}
matrix3 = matrix2 + matrix1;
cout << "Echoing the 2 dim array, sum of matrix 1 and 2\n";
cout << "rows " << myRows(matrix3) << " "
<< "cols " << myCols(matrix3) << endl;
for (i = 0; i < myRows(matrix3); i++)
{
for (j = 0; j < myCols(matrix3); j++)
{
// cout << "i,j " << i << " " << j << " ";
cout << matrix3(i,j) << " ";
}
cout << endl;
}
return 0;
}
int myRows(const TwoD& arg){ return arg.maxRows;}
int myCols(const TwoD& arg){ return arg.maxCols;}
TwoD operator+(const TwoD& lhs, const TwoD& rhs)
{
if(lhs.maxRows != rhs.maxRows || lhs.maxCols != rhs.maxCols)
{
cout << "Matrices not same size "
<< " lhs matrix row, col sizes "
<< lhs.maxRows << " " << lhs.maxCols << endl
<< "rhs matrix row, col sizes "
<< rhs.maxRows << " " << rhs.maxCols << endl;
exit(1); // Die if matrices not same.
}
//sizes are same
TwoD sum(lhs.maxRows, lhs.maxCols);
for(int i = 0; i < lhs.maxRows; i++)
for(int j = 0; j < lhs.maxCols; j++)
sum.matrix[i][j] = rhs.matrix[i][j] + lhs.matrix[i][j];
return sum;
}
double& TwoD::operator()(int r, int c) // returns row r, col c element
{
return matrix[r][c];
}
const TwoD& TwoD::operator=(const TwoD& rhs)
{
if(matrix == rhs.matrix)
return rhs; // lhs == rhs, do nothing
//lhs != rhs, blow away lhs
for(int i = 0; i < maxRows; i++)
delete[] matrix[i];
delete[] matrix;
maxRows = rhs.maxRows;
maxCols = rhs.maxCols;
//reallocate
matrix = new DoubleArrayPtr[maxRows];
for(int i = 0; i < maxRows; i++)
matrix[i] = new double[maxCols];
//deep copy
for(int i = 0; i < maxRows; i++)
for(int j = 0; j < maxCols; j++)
matrix[i][j] = rhs.matrix[i][j];
return rhs;
}
TwoD::TwoD(const TwoD& rhs)
: maxRows(rhs.maxRows), maxCols(rhs.maxCols)
{
matrix = new DoubleArrayPtr[maxRows];
for(int i = 0; i < maxRows; i++)
matrix[i] = new double[maxCols];
for(int i = 0; i < maxRows; i++)
for(int j = 0; j < maxCols; j++)
matrix[i][j] = rhs.matrix[i][j];
}
TwoD::~TwoD()
{
for(int i = 0; i < maxRows; i++)
delete[] matrix[i];
delete[] matrix;
}
TwoD::TwoD() : maxRows(10), maxCols(10)
{
matrix = new DoubleArrayPtr[maxRows];
for(int i = 0; i < maxRows; i++)
matrix[i] = new double[maxCols];
for(int i = 0; i < maxRows; i++)
for(int j = 0; j < maxCols; j++)
matrix[i][j] = 0;
}
TwoD::TwoD(int maxR, int maxC ) : maxRows(maxR), maxCols(maxC)
{
matrix = new DoubleArrayPtr[maxRows];
for(int i = 0; i < maxR; i++)
matrix[i] = new double[maxCols];
for(int i = 0; i < maxRows; i++)
for(int j = 0; j < maxCols; j++)
matrix[i][j] = 0;
}
/*
I usually use the command line to execute with input redirected
from a file. It is easier than typing in the data every time:
ch10prog1 < ch10prog1Data.txt > ch10prog1out.txt
With this data:
3 4
1.0 2.0 3.0 4.0
5.0 6.0 7.0 8.0
9.0 8.0 1.0 2.0
3 4
1.0 1.0 1.0 1.0
-1.0 -1.0 -1.0 -1.0
2.0 2.0 2.0 2.0
A run of this produces this output:
Enter the row and column dimensions of the array
Enter 3 rows of 4 doubles each
Echoing the 2 dim. array, matix1
1 2 3 4
5 6 7 8
9 8 1 2
Enter the row and column dimensions of the array
Enter 3 rows of 4 doubles each
Echoing the 2 dim. array, matrix2
1 1 1 1
-1 -1 -1 -1
2 2 2 2
assigning matrix 2 to matrix 3
Displaying the 2 dim array, matrix3 resulting from assignmnet.
rows 3 cols 4
1 1 1 1
-1 -1 -1 -1
2 2 2 2
Echoing the 2 dim array, sum of matrix 1 and 2
rows 3 cols 4
2 3 4 5
4 5 6 7
11 10 3 4
*/
2. Polynomial class.
Using dynamic arrays, implement a polynomial class with infix operators +, -, *.
Discussion:
In a polynomial, a variable is placeholder for coefficient. If term is missing, the coefficient is 0. For example, the cubic polynomial
2x3 -3x + 4
or, written out as C++ code,
2*x*x*x –3*x + 4
has the coefficients for terms as listed:
degree 3 term has coefficient 2,
degree 2 term has coefficient 0,
degree 1 term has coefficient -3, and
degree 0 term has coefficient 4.
Note that the term with degree 2 is missing, but we will use a coefficient of 0 to indicate that. Observe that the size of the coefficient array is 4, one more than the degree.
Use of sparse matrix techniques not recommended. We will assume that there are few missing terms.
The student is to provide these member functions:
-
default constructor,
-
copy constructor,
-
operator=
-
destructor
-
parameterized constructor to create an arbitrary polynomial
-
operator+
-
operator-
-
operator*
-
assign and inspect function (or functions) for
-
coefficients, indexed by exponent
-
function to evaluate polynomial as a value of type double
The student is to decide on whether these are to be member, friend, or neither
(standalone).
NOTES:
The default constructor creates an empty polynomial. A zero polynomial has degree 0, since it has only the zero degree coefficient.
In the coefficient array, the index is the value of the exponent of term having this coefficient. For example, the index 0 entry is the constant coefficient, the index 1 entry is coefficient of the linear term, the index 2 entry is the coefficient of the quadratic term (term in x2), etc.
The size of the coefficient array include a degree 0 entry, so the size is the degree of the polynomial + 1.
Odd error messages associated with overloading some of the operators occur if you try to pass a Polynomial object to one of the functions by const reference and do not implement both these operator[] implementations,
//This version of operator[] is used when an indexed
//expression is used as an l-value.
double& operator[](int degree);
//This version of operator[] is used when an indexed
//expression is used as an r-value.
const double& operator[](int degree)const;
Instead of difficult-to-understand compiler error messages, you may get linker errors, which is an even harder situation, since linker errors are not associated with any particular line in your source.
The alternative is to pass by value. In this example, that is not a problem but in general, passing a class object has the potential for a large amount of copying of data, so const reference is the desirable way to do it.
Neither of the operator functions for multiply, add or subtract check for zero lead coefficients. For polynomials that have many zero terms, these functions should account for the zero entries. Two polynomials of high degree with few nonzero terms will waste considerable time multiplying zero entries using this technique. The fix is the use of a linked list (Chapter 17), or the STL list (Chapter 19.)
My solution follows:
//file: ch10Prog2.cpp
//Polynomial class -- Chapter 10 Programming Problem #2
#include
using namespace std;
class Polynomial
{
public:
Polynomial(); // creates an empty polynomial
Polynomial(const Polynomial&);
// The size of the coefficient array is degree of the polynomial + 1.
Polynomial(double coefficient[], int size);
~Polynomial();
//Use indexed polynomial as r-value to inspect coefficient
//and as l-value to assign coefficient
double& operator[](int degree);
//This is required if we are to have const correctness
const double& operator[](int degree)const;
const Polynomial& operator=(const Polynomial & rhs);
int misuse();
//friend functions:
friend double evaluate(const Polynomial& ploy, double arg);
friend Polynomial operator+(const Polynomial& lsh,
const Polynomial& rhs);
friend Polynomial operator-(const Polynomial& lsh,
const Polynomial& rhs);
friend Polynomial operator*(const Polynomial& lsh,
const Polynomial& rhs);
private:
double * coef;
int size;
};
int main()
{
Polynomial empty;
double one[] = {1};
Polynomial One(one, 1);
double quad[] = {3, 2, 1};
double cubic[] = {1, 2, 0, 3};
Polynomial q(quad, 3); // q is 3 + 2*x + x*x
Polynomial c(cubic, 4);// c is 1 + 2*x + 0*x*x + 3*x*x*x
Polynomial p = q; // test copy constructor
Polynomial r;
r = q; //test operator=
r = c;
cout << "Polynomial q " << endl;
{for(int i = 0; i < 3; i++)
cout << "term with degree " << i
<< " has coefficient " << q[i] << endl;
}
cout << "Polynomial c " << endl;
{for(int i = 0; i < 4; i++)
cout << "term with degree " << i
<< " has coefficient " << c[i] << endl;
}
cout << "value of q(2) is " << evaluate(q, 2) << endl;
cout << "value of p(2) is " << evaluate(p, 2) << endl;
cout << "value of r(2) is " << evaluate(r, 2) << endl;
cout << "value of c(2) is " << evaluate(c, 2) << endl;
r = q + c;
cout << "value of (q + c)(2) is " << evaluate(r, 2) << endl;
r = q - c;
cout << "value of (q - c)(2) is " << evaluate(r, 2) << endl;
r = q * c;
cout << "size of q*c is " << r.mySize() << endl;
cout << "Polynomial r (= q*c) " << endl;
for(int i = 0; i < r.mySize(); i++)
cout << "term with degree " << i
<< " has coefficient " << r[i] << endl;
cout << "value of (q * c)(2) is " << evaluate(r, 2) << endl;
return 0;
}
int Polynomial::mySize()
{
return size;
}
// creates an empty polynomial
Polynomial::Polynomial():coef(0), size(0)
{// deliberately empty
}
const Polynomial& Polynomial::operator=(const Polynomial & rhs)
{
if(rhs.coef == coef) //if both coefficient arrays start at the same
return rhs; //place our two Polynomials are the same.
else
{
delete [] coef;
coef = new double[rhs.size];
for(int i = 0; i < rhs.size; i++)
coef[i] = rhs.coef[i];
size = rhs.size;
}
return rhs;
}
Polynomial::Polynomial(const Polynomial& rhs) : size(rhs.size)
{
coef = new double[rhs.size];
for(int i = 0; i < rhs.size; i++)
coef[i] = rhs.coef[i];
}
Polynomial::Polynomial(double coefficient[],
int newSize) : size(newSize)
{
coef = new double[size];
for(int i = 0; i < size; i++)
coef[i] = coefficient[i];
}
Polynomial::~Polynomial()
{
delete [] coef;
}
//return the coefficient of term in variable to exponent 'degree'
const double& Polynomial::operator[](int degree) const
{
return coef[degree];
}
double& Polynomial::operator[](int degree)
{
return coef[degree];
}
double max(double lhs, double rhs)
{
return (lhs > rhs) ? lhs : rhs;
}
// friend function and operator function implementations
Polynomial operator+(const Polynomial& lhs, const Polynomial& rhs)
{
const int sumSize = max(lhs.size, rhs.size);
double* sumCoefs = new double[sumSize];
for(int i = 0; i < sumSize; i++)
sumCoefs[i] = lhs.coef[i] + rhs.coef[i];
return Polynomial(sumCoefs, sumSize);
}
Polynomial operator-(const Polynomial& lhs, const Polynomial& rhs)
{
int sumSize = max(lhs.size, rhs.size);
double* sumCoefs = new double[sumSize];
for(int i = 0; i < sumSize; i++)
sumCoefs[i] = lhs.coef[i] - rhs.coef[i];
return Polynomial(sumCoefs, sumSize);
}
// Notes:
// The multiplication routine does not check for zero lead
// coefficients. It also assumes few zero terms.
Polynomial operator*(const Polynomial& lhs, const Polynomial& rhs)
{
int i; int j;
int prodSize = lhs.size + rhs.size;
double* prodCoefs = new double[prodSize];
for(i = 0; i < prodSize; i++)
prodCoefs[i] = 0;
for(i = 0; i < lhs.size; i++)
for(j = 0; j < rhs.size; j++)
prodCoefs[i + j] += lhs[i] * rhs[j];
return Polynomial(prodCoefs, prodSize);
}
double evaluate(const Polynomial& poly, double arg)
{
double value = 0;
int i;
for(i = poly.size - 1; i >= 0; i--)
value = poly[i] + arg * value;
return value;
}
This is the output from this program follows.
Polynomial q
term with degree 0 has coefficient 3
term with degree 1 has coefficient 2
term with degree 2 has coefficient 1
Polynomial c
term with degree 0 has coefficient 1
term with degree 1 has coefficient 2
term with degree 2 has coefficient 0
term with degree 3 has coefficient 3
value of q(2) is 11
value of p(2) is 11
value of r(2) is 29
value of c(2) is 29
value of (q + c)(2) is 40
value of (q - c)(2) is -18
size of q*c is 7
Polynomial r (= q*c)
term with degree 0 has coefficient 3
term with degree 1 has coefficient 8
term with degree 2 has coefficient 5
term with degree 3 has coefficient 11
term with degree 4 has coefficient 6
term with degree 5 has coefficient 3
term with degree 6 has coefficient 0
value of (q * c)(2) is 319