aditya86b
asked on
array class operator oveloading
How can I add three more additional operators for the following program.
// Fig. 11.8: fig11_08.cpp
// Array class test program.
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include "Array.h"
int main()
{
Array integers1( 7 ); // seven-element Array
Array integers2; // 10-element Array by default
// print integers1 size and contents
cout << "Size of Array integers1 is "
<< integers1.getSize()
<< "\nArray after initialization:\n" << integers1;
// print integers2 size and contents
cout << "\nSize of Array integers2 is "
<< integers2.getSize()
<< "\nArray after initialization:\n" << integers2;
// input and print integers1 and integers2
cout << "\nEnter 17 integers:" << endl;
cin >> integers1 >> integers2;
cout << "\nAfter input, the Arrays contain:\n"
<< "integers1:\n" << integers1
<< "integers2:\n" << integers2;
// use overloaded inequality (!=) operator
cout << "\nEvaluating: integers1 != integers2" << endl;
if ( integers1 != integers2 )
cout << "integers1 and integers2 are not equal" << endl;
// create Array integers3 using integers1 as an
// initializer; print size and contents
Array integers3( integers1 ); // invokes copy constructor
cout << "\nSize of Array integers3 is "
<< integers3.getSize()
<< "\nArray after initialization:\n" << integers3;
// use overloaded assignment (=) operator
cout << "\nAssigning integers2 to integers1:" << endl;
integers1 = integers2; // note target Array is smaller
cout << "integers1:\n" << integers1
<< "integers2:\n" << integers2;
// use overloaded equality (==) operator
cout << "\nEvaluating: integers1 == integers2" << endl;
if ( integers1 == integers2 )
cout << "integers1 and integers2 are equal" << endl;
// use overloaded subscript operator to create rvalue
cout << "\nintegers1[5] is " << integers1[ 5 ];
// use overloaded subscript operator to create lvalue
cout << "\n\nAssigning 1000 to integers1[5]" << endl;
integers1[ 5 ] = 1000;
cout << "integers1:\n" << integers1;
// attempt to use out-of-range subscript
cout << "\nAttempt to assign 1000 to integers1[15]" << endl;
integers1[ 15 ] = 1000; // ERROR: out of range
return 0;
} // end main
/**************************************************************************
* (C) Copyright 1992-2005 by Deitel & Associates, Inc. and *
* Pearson Education, Inc. All Rights Reserved. *
* *
* DISCLAIMER: The authors and publisher of this book have used their *
* best efforts in preparing the book. These efforts include the *
* development, research, and testing of the theories and programs *
* to determine their effectiveness. The authors and publisher make *
* no warranty of any kind, expressed or implied, with regard to these *
* programs or to the documentation contained in these books. The authors *
* and publisher shall not be liable in any event for incidental or *
* consequential damages in connection with, or arising out of, the *
* furnishing, performance, or use of these programs. *
**************************************************************************/
// Fig 11.7: Array.cpp
// Member-function definitions for class Array
#include <iostream>
using std::cerr;
using std::cout;
using std::cin;
using std::endl;
#include <iomanip>
using std::setw;
#include <cstdlib> // exit function prototype
using std::exit;
#include "Array.h" // Array class definition
// default constructor for class Array (default size 10)
Array::Array( int arraySize )
{
size = ( arraySize > 0 ? arraySize : 10 ); // validate arraySize
ptr = new int[ size ]; // create space for pointer-based array
for ( int i = 0; i < size; i++ )
ptr[ i ] = 0; // set pointer-based array element
} // end Array default constructor
// copy constructor for class Array;
// must receive a reference to prevent infinite recursion
Array::Array( const Array &arrayToCopy )
: size( arrayToCopy.size )
{
ptr = new int[ size ]; // create space for pointer-based array
for ( int i = 0; i < size; i++ )
ptr[ i ] = arrayToCopy.ptr[ i ]; // copy into object
} // end Array copy constructor
// destructor for class Array
Array::~Array()
{
delete [] ptr; // release pointer-based array space
} // end destructor
// return number of elements of Array
int Array::getSize() const
{
return size; // number of elements in Array
} // end function getSize
// overloaded assignment operator;
// const return avoids: ( a1 = a2 ) = a3
const Array &Array::operator=( const Array &right )
{
if ( &right != this ) // avoid self-assignment
{
// for Arrays of different sizes, deallocate original
// left-side array, then allocate new left-side array
if ( size != right.size )
{
delete [] ptr; // release space
size = right.size; // resize this object
ptr = new int[ size ]; // create space for array copy
} // end inner if
for ( int i = 0; i < size; i++ )
ptr[ i ] = right.ptr[ i ]; // copy array into object
} // end outer if
return *this; // enables x = y = z, for example
} // end function operator=
// determine if two Arrays are equal and
// return true, otherwise return false
bool Array::operator==( const Array &right ) const
{
if ( size != right.size )
return false; // arrays of different number of elements
for ( int i = 0; i < size; i++ )
if ( ptr[ i ] != right.ptr[ i ] )
return false; // Array contents are not equal
return true; // Arrays are equal
} // end function operator==
// overloaded subscript operator for non-const Arrays;
// reference return creates a modifiable lvalue
int &Array::operator[]( int subscript )
{
// check for subscript out-of-range error
if ( subscript < 0 || subscript >= size )
{
cerr << "\nError: Subscript " << subscript
<< " out of range" << endl;
exit( 1 ); // terminate program; subscript out of range
} // end if
return ptr[ subscript ]; // reference return
} // end function operator[]
// overloaded subscript operator for const Arrays
// const reference return creates an rvalue
int Array::operator[]( int subscript ) const
{
// check for subscript out-of-range error
if ( subscript < 0 || subscript >= size )
{
cerr << "\nError: Subscript " << subscript
<< " out of range" << endl;
exit( 1 ); // terminate program; subscript out of range
} // end if
return ptr[ subscript ]; // returns copy of this element
} // end function operator[]
// overloaded input operator for class Array;
// inputs values for entire Array
istream &operator>>( istream &input, Array &a )
{
for ( int i = 0; i < a.size; i++ )
input >> a.ptr[ i ];
return input; // enables cin >> x >> y;
} // end function
// overloaded output operator for class Array
ostream &operator<<( ostream &output, const Array &a )
{
int i;
// output private ptr-based array
for ( i = 0; i < a.size; i++ )
{
output << setw( 12 ) << a.ptr[ i ];
if ( ( i + 1 ) % 4 == 0 ) // 4 numbers per row of output
output << endl;
} // end for
if ( i % 4 != 0 ) // end last line of output
output << endl;
return output; // enables cout << x << y;
} // end function operator<<
/**************************************************************************
* (C) Copyright 1992-2005 by Deitel & Associates, Inc. and *
* Pearson Education, Inc. All Rights Reserved. *
* *
* DISCLAIMER: The authors and publisher of this book have used their *
* best efforts in preparing the book. These efforts include the *
* development, research, and testing of the theories and programs *
* to determine their effectiveness. The authors and publisher make *
* no warranty of any kind, expressed or implied, with regard to these *
* programs or to the documentation contained in these books. The authors *
* and publisher shall not be liable in any event for incidental or *
* consequential damages in connection with, or arising out of, the *
* furnishing, performance, or use of these programs. *
**************************************************************************/
// Fig. 11.8: fig11_08.cpp
// Array class test program.
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include "Array.h"
int main()
{
Array integers1( 7 ); // seven-element Array
Array integers2; // 10-element Array by default
// print integers1 size and contents
cout << "Size of Array integers1 is "
<< integers1.getSize()
<< "\nArray after initialization:\n" << integers1;
// print integers2 size and contents
cout << "\nSize of Array integers2 is "
<< integers2.getSize()
<< "\nArray after initialization:\n" << integers2;
// input and print integers1 and integers2
cout << "\nEnter 17 integers:" << endl;
cin >> integers1 >> integers2;
cout << "\nAfter input, the Arrays contain:\n"
<< "integers1:\n" << integers1
<< "integers2:\n" << integers2;
// use overloaded inequality (!=) operator
cout << "\nEvaluating: integers1 != integers2" << endl;
if ( integers1 != integers2 )
cout << "integers1 and integers2 are not equal" << endl;
// create Array integers3 using integers1 as an
// initializer; print size and contents
Array integers3( integers1 ); // invokes copy constructor
cout << "\nSize of Array integers3 is "
<< integers3.getSize()
<< "\nArray after initialization:\n" << integers3;
// use overloaded assignment (=) operator
cout << "\nAssigning integers2 to integers1:" << endl;
integers1 = integers2; // note target Array is smaller
cout << "integers1:\n" << integers1
<< "integers2:\n" << integers2;
// use overloaded equality (==) operator
cout << "\nEvaluating: integers1 == integers2" << endl;
if ( integers1 == integers2 )
cout << "integers1 and integers2 are equal" << endl;
// use overloaded subscript operator to create rvalue
cout << "\nintegers1[5] is " << integers1[ 5 ];
// use overloaded subscript operator to create lvalue
cout << "\n\nAssigning 1000 to integers1[5]" << endl;
integers1[ 5 ] = 1000;
cout << "integers1:\n" << integers1;
// attempt to use out-of-range subscript
cout << "\nAttempt to assign 1000 to integers1[15]" << endl;
integers1[ 15 ] = 1000; // ERROR: out of range
return 0;
} // end main
/**************************************************************************
* (C) Copyright 1992-2005 by Deitel & Associates, Inc. and *
* Pearson Education, Inc. All Rights Reserved. *
* *
* DISCLAIMER: The authors and publisher of this book have used their *
* best efforts in preparing the book. These efforts include the *
* development, research, and testing of the theories and programs *
* to determine their effectiveness. The authors and publisher make *
* no warranty of any kind, expressed or implied, with regard to these *
* programs or to the documentation contained in these books. The authors *
* and publisher shall not be liable in any event for incidental or *
* consequential damages in connection with, or arising out of, the *
* furnishing, performance, or use of these programs. *
**************************************************************************/
ASKER
suppose addition operator or subtraction
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
>> Chains work fine with const return references.
Yes, you're right (my head was in the clouds there); however, I still don't agree with it for the following reason...
Firstly, let's take the implementation of the std::vector's assignment operator as an example...
_Myt& operator=(const _Myt& _Right); // Does not return const reference
Secondly, it means the assignment semantics will not be the same as the standard built-in or synthesised assignment operators. This can impact ones ability to write generic code as the behaviour would be unexpected.
Yes, you're right (my head was in the clouds there); however, I still don't agree with it for the following reason...
Firstly, let's take the implementation of the std::vector's assignment operator as an example...
_Myt& operator=(const _Myt& _Right); // Does not return const reference
Secondly, it means the assignment semantics will not be the same as the standard built-in or synthesised assignment operators. This can impact ones ability to write generic code as the behaviour would be unexpected.
template <typename T>
void bar(T & t)
{
}
template <typename T>
void foo(T & t1, T & t2, T & t3)
{
(t1 = t2) = t3;
bar(t3 = t1);
}
struct ArrayBad
{
const ArrayBad & operator=( const ArrayBad &right )
{
return *this;
}
};
struct ArrayGood
{
ArrayGood &operator=( const ArrayGood &right )
{
return *this;
}
};
struct Default{};
int main()
{
int i1, i2, i3;
foo(i1, i2, i3);
Default d1, d2, d3;
foo(d1, d2, d3);
ArrayGood ag1, ag2, ag3;
foo(ag1, ag2, ag3);
// This class has wrong assignment semantics, it doesn't behave like built-in types
// not does the assignment operator behave like a compiler synthersised operator
ArrayBad ab1, ab2, ab3;
foo(ab1, ab2, ab3);
}
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
>> the return value should be non-const. As it is a temporary array
What should be returned is a non-const reference to *this
What should be returned is a non-const reference to *this
>>>> What should be returned is a non-const reference to *this
No. The operator+ returns a new Array by Value. The operator+= would return a non-const reference to this ...
No. The operator+ returns a new Array by Value. The operator+= would return a non-const reference to this ...
>> No. The operator+ returns a new Array by Value.
Yes as it should and as I have already pointed out above where I state, "Note that you must return a copy of a new object because the standard + and - operators shouldn't modify the original objects".
However, I was refering to this comment you made...
">>>> const Array &Array::operator=( const Array &right )
I agree with evilrix that the return value should be non-const. As it is a temporary array only which only lives within the current scope"
Clearly, and operator=() should not return a temporary, it returns a reference to *this and, as we both agree, it should be non-const.
I think we are just talking at cross purposes, but I don't want to confuse aditya86b. :)
Yes as it should and as I have already pointed out above where I state, "Note that you must return a copy of a new object because the standard + and - operators shouldn't modify the original objects".
However, I was refering to this comment you made...
">>>> const Array &Array::operator=( const Array &right )
I agree with evilrix that the return value should be non-const. As it is a temporary array only which only lives within the current scope"
Clearly, and operator=() should not return a temporary, it returns a reference to *this and, as we both agree, it should be non-const.
I think we are just talking at cross purposes, but I don't want to confuse aditya86b. :)
> however, I still don't agree with it for the following reason...
I agree with you, evilrix, for an Array class. I expect if Dietel had another 13 years to work on that code, they might change their position too ;-)
I agree with you, evilrix, for an Array class. I expect if Dietel had another 13 years to work on that code, they might change their position too ;-)
>>>> I agree with evilrix that the return value should be non-const.
Sorry, you are right. I was mixing up operator= and operator+ (and possibly have confused the asker).
It isn't quite easy to find an example where the const return of operator= does any harm though ...
(a.operator=(a1)).append(1 2345);
wouldn't compile but I don't know whether that is a statement of relevance ...
(a = a1).append(98765);
compiles if a is a non-const Array.
Sorry, you are right. I was mixing up operator= and operator+ (and possibly have confused the asker).
It isn't quite easy to find an example where the const return of operator= does any harm though ...
(a.operator=(a1)).append(1
wouldn't compile but I don't know whether that is a statement of relevance ...
(a = a1).append(98765);
compiles if a is a non-const Array.
>> It isn't quite easy to find an example where the const return of operator= does any harm though
It's not so much harm as semantically incorrect in terms of it doesn't fit with the standard nor compiler synthesised operators and, as I point out, this could be problematic when writing generic code. That said, the problem it tries to address is reasonable; however, (a) is it really a problem? and (b) even if it is since you can still do it with integral and compiler synthesized types changing your own types to behave differently is just going to confuse.
So to sum up, I applaud the idea (I think, although I'd have to check, Scott Meyer advocates doing this, or something like it); however, personally I prefer my semantics consistent even if they aren't wholly correct :)
It's not so much harm as semantically incorrect in terms of it doesn't fit with the standard nor compiler synthesised operators and, as I point out, this could be problematic when writing generic code. That said, the problem it tries to address is reasonable; however, (a) is it really a problem? and (b) even if it is since you can still do it with integral and compiler synthesized types changing your own types to behave differently is just going to confuse.
So to sum up, I applaud the idea (I think, although I'd have to check, Scott Meyer advocates doing this, or something like it); however, personally I prefer my semantics consistent even if they aren't wholly correct :)
What operators? Added to what?
See if these links help.
Operator overloading
http://www.parashift.com/c++-faq-lite/operator-overloading.html
C++ Operator Overloading Guidelines
http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html