3 Replies - 5940 Views - Last Post: 21 May 2011 - 03:18 AM Rate Topic: -----

#1 munitjsr2   User is offline

  • New D.I.C Head

Reputation: -1
  • View blog
  • Posts: 35
  • Joined: 02-April 11

overloading operator [] twice to represent a call by rvalue or lvalue

Posted 20 May 2011 - 10:53 AM

Array.h
// Array class definition with overloaded operators.
#ifndef ARRAY_H
#define ARRAY_H

#include <iostream>
using std::ostream;
using std::istream;

class Array
{
   friend ostream &operator<<( ostream &, const Array & );
   friend istream &operator>>( istream &, Array & );
public:
   Array( int = 5 ); // default constructor
   Array( const Array & ); // copy constructor
   ~Array(); // destructor
   int getSize() const; // return size

   const Array &operator=( const Array & ); // assignment operator
   bool operator==( const Array & ) const; // equality operator

   // inequality operator; returns opposite of == operator
   bool operator!=( const Array &right ) const  
   { 
      return ! ( *this == right ); // invokes Array::operator==
   } // end function operator!=
   
   // subscript operator for non-const objects returns modifiable lvalue
   int &operator[]( int );              

   // subscript operator for const objects returns rvalue
   int operator[]( int ) const;  
private:
   int size; // pointer-based array size
   int *ptr; // pointer to first element of pointer-based array
}; // end class Array

#endif



Array.cpp
// Array class member- and friend-function definitions.
#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 5)
Array::Array( int arraySize )
{
   size = ( arraySize > 0 ? arraySize : 5 ); // 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<<



main.cpp
// Array class test program.
#include <iostream>
using std::cout;
using std::cin;
using std::endl;

#include "Array.h"

int main()
{
   Array integers1( 4 ); // seven-element Array
   Array integers2; // 5-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 9 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[ 3 ];

   // use overloaded subscript operator to create lvalue
   cout << "\n\nAssigning 1000 to integers1[5]" << endl;
   integers1[ 3 ] = 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



The program is a simple implementation of vector class(templates are not used) but still I am unable to understand
why the operater [] is overloaded to have two versions const and non-const.

I placed the below lines in both those([] overloaded) functions just to test which is being called when.
In the const version of the overloaded operator
cout << " ***************Inside constant operator[] function: Rvalue test*********** ";


In the non-const version of the overloaded operator
cout << " ***************Inside non-sonstant operator[] function: Lvalue test*********** ";


and found that everytime the non-constant version of the object is called.

I guess the only way the constant version of the object is called when I declare a constant object
say const Array integers1( 4 ) but then also its of no use I guess.

Please give some understanding on this..

This post has been edited by munitjsr2: 20 May 2011 - 11:20 AM


Is This A Good Question/Topic? 0
  • +

Replies To: overloading operator [] twice to represent a call by rvalue or lvalue

#2 ishkabible   User is offline

  • spelling expret
  • member icon





Reputation: 1749
  • View blog
  • Posts: 5,901
  • Joined: 03-August 09

Re: overloading operator [] twice to represent a call by rvalue or lvalue

Posted 20 May 2011 - 11:51 AM

pass it as a constant reference.

void foo(const Array& a) {
   cout << "\nintegers1[5] is " << integers1[3];
}


Was This Post Helpful? 1
  • +
  • -

#3 munitjsr2   User is offline

  • New D.I.C Head

Reputation: -1
  • View blog
  • Posts: 35
  • Joined: 02-April 11

Re: overloading operator [] twice to represent a call by rvalue or lvalue

Posted 20 May 2011 - 12:08 PM

View Postishkabible, on 20 May 2011 - 11:51 AM, said:

pass it as a constant reference.

void foo(const Array& a) {
   cout << "\nintegers1[5] is " << integers1[3];
}



thanks, it works..so the variable is converting to a const array when passed as a const reference.right

like

const Array& a = integers1;

this implies--> integers1 converted to a constant is it??

This post has been edited by munitjsr2: 20 May 2011 - 12:22 PM

Was This Post Helpful? 0
  • +
  • -

#4 Bench   User is offline

  • D.I.C Lover
  • member icon

Reputation: 945
  • View blog
  • Posts: 2,464
  • Joined: 20-August 07

Re: overloading operator [] twice to represent a call by rvalue or lvalue

Posted 21 May 2011 - 03:18 AM

View Postmunitjsr2, on 20 May 2011 - 08:08 PM, said:

const Array& a = integers1;

this implies--> integers1 converted to a constant is it??
The only thing which is const is the reference called a.

Its not a 'conversion' since the original integers1 object itself does not change; The reference provides you with an interface which the compiler will let you use to access the object with - except that the compiler will restrict you to const member functions and other non-modifying operations for the object when you use a.

When passing by const-reference, think of it like a contract between you and the compiler. You are promising not to make any changes to the object via that reference. (However, the original object, which may not be const may still change somewhere else in the code).



For example, it would be possible to pass the same object by reference and by const-reference to the same function; even though both references would refer to the same object, their interfaces would be different, and the object would be modifiable inside that function through the non-const interface. e.g.
#include <string>
#include <iostream>

void foo(std::string& first, const std::string& second)
{
    first += ", world!";
    std::cout << second << std::endl;
}

int main()
{
    std::string fred("hello");
    foo(fred, fred);
} 
Even though the foo() function cannot change second, the output is still "hello, world!".

This post has been edited by Bench: 21 May 2011 - 03:31 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1