hey all,

i'm working on a very simplistic example to revive my cpp skills for an up coming work placement. however i'm running into what seems an inconsistant error using ostream (cout)... have a look at the following code in the main()...

:: main.cpp ::

#include <iostream>
#include "IntArray.h"

using namespace std;

int main()
{
    IntArray a(7);
    for(int i = 0; i < a.getNumElements(); i++) a[i] = i * i;
    cout << a << endl << endl;

    IntArray b(4);
    for(int i = 0; i < b.getNumElements(); i++) b[i] = i - (2 * i) * i;
    cout << b << endl << endl;
    
    // THIS WORKS
    b = b + a + b + a;
    cout << b << endl;

    // BUT THIS  DOESN'T
    cout << (b + a) << endl;
}

the compiler error is as follows: /home/allsey/Programming/testa/main.cpp|19|error: no match for ‘operator<<’ in ‘std::cout << IntArray::operator+(const IntArray&)(((const IntArray&)((const IntArray*)(& a))))’| it seems from this error, that ostream is looking for a method to print out the operator as aposed to its return type... does any one know what is going on here? - i'm also open to any sugestions about my style of implementing these operators and whether there is any room for improvement.

here is the rest of the code:

:: IntArray.h ::

#ifndef INTARRAY_H
#define INTARRAY_H

#include <stdexcept>

class IntArray
{
    friend std::ostream & operator<<(std::ostream & toStream, IntArray & theArray);

    public:
        IntArray(int size); // std constructor
        IntArray(const IntArray & other); // copy constructor
        IntArray(const IntArray &first, const IntArray &last); // concat constructor

        ~IntArray(); // destructor

        int getNumElements() const;

        int & operator[](int index);
        IntArray operator-(IntArray & toNegate); // TO BE IMPLEMENTED
        IntArray operator+(const IntArray & toConcat); // concat operator
        IntArray operator=(const IntArray & toAssign);

    private:
        int * data;
        int numElements;
};

#endif

:: IntArray.cpp ::

#include <ostream>

#include "IntArray.h"

IntArray::IntArray(int size)
{
    data = new int[size];
    numElements = size;
    for(int i = 0; i < size; i++) data[i] = 0;
}

IntArray::IntArray(const IntArray & other)
{
    data = new int[other.numElements];
    numElements = other.numElements;
    for(int i = 0; i < other.numElements; i++) data[i] = other.data[i];
}

IntArray::IntArray(const IntArray &first, const IntArray &last) // concat constructor
{
    data = new int[first.numElements + last.numElements];
    numElements = first.numElements + last.numElements;
    for(int i = 0; i < first.numElements; i++)
    {
        data[i] = first.data[i];
    }
    for(int i = 0; i < last.numElements; i++)
    {
        data[i + first.numElements] = last.data[i];
    }
}

IntArray::~IntArray()
{
    delete []data;
}

int IntArray::getNumElements() const
{
    return numElements;
}

int & IntArray::operator[](int index)
{
    if(index < 0 || index > (numElements - 1)) throw std::out_of_range("bad index");
    else return data[index];
}

IntArray IntArray::operator+(const IntArray & toConcat) // concat operator
{
    return IntArray(*this,toConcat);
}

IntArray IntArray::operator=(const IntArray & toAssign) // concat operator
{
    delete []data;
    data = new int[toAssign.numElements];
    numElements = toAssign.numElements;
    for(int i = 0; i < toAssign.numElements;i++)
    {
        data[i] = toAssign.data[i];
    }
    return *this;
}

std::ostream & operator<<(std::ostream & toStream, IntArray & theArray)
{
    toStream << "{";
    for(int i = 0; i < theArray.numElements - 1; i++) toStream << theArray.data[i] << ", ";
    toStream << theArray.data[theArray.numElements - 1] << "}";
    return toStream;
}

Try having your operator<< method take in a const IntArray& instead.

when you use << it looks for a method to ouput the data. since you are trying to output the class the compiler looks for a method to ouput but since yo dont have one you are getting this error. you need to overload the << operator so it displays the data of the class.

// class functions declerations
friend ostream & operator <<(ostream & out, IntArray & array);
// more class functions
//...
//class definitions
ostream & IntArray::operator <<(ostream & out, IntArray & array)
{
 for (int i = 0; i < numElements; i++)
 {
   cout << data[numElements] << "\n";
 }
 return out;
}

not only will this ouput the data of the class but since it returns an ostream reference you can write statements like cout << a << endl << b << endl << c << endl; otherwise you would have to output each class one at a time

Thanks guys for the quick replys:

That wasn't the problem NathanOliver, the method for operator<< was provided as shown in the code right at the end of my first post.

however, I changed the operator<< to take in const & and it worked perfectly! - thanks DLUZ

can anyone explain though why this was, what is the subtle c++ rule behind this... note, i agree that the parameter should be a const as per data encapsulation rule of thumb, but why was this a requirement for it to work?

by the way NathanOliver, two things that you and others reading this post should be aware of
1. when writing operator<< methods, always write std::ostream a << argument , and not cout << argument - this allows the extraction operator to be used with files, and stringstreams as well as the ostream instance 'cout' as defined in iostream.

2. this one is a matter of style and opinion, i generally avoid using using namespace std; as it floods the namespace of your program, although some would argue that it increase readability of the code, i'd argue that using std:: shows exactly where the variable or method is located. and i'm sure of the behaviour if you decide to use multiple namespaces inside your application

Hey allsey_1987,

I'm glad the const thing worked. I'm sorry for the quick post but I was on my way out.
The reason it worked was this:

Your operator+ returns an IntArray so you might think that you're getting an IntArray in your operator<<.
That is actually the case in your first example
IntArray b(4);
(...)
b = b + a + b + a;
cout << b << endl;

It's not the case in your second one though
cout << (b + a) << endl;
The IntArray object that's returned from your (b+a) operation is an un-named temporary object whose scope is basically that line. Those kinds of objects are const.

That's why your operator<< needs to take a const IntArray reference to work in that situation.

Another situation that wouldn't work without the const is something like:
cout << IntArray( 3 );

You might not need to print out a newly created array anyway, but it's just an example :)

So literals and temp nameless variables are const and functions that should take them as parameters need to declare them as const too.

An example with literals:
void foo( int& i )
{ (...) }

int bar = 3;
foo( bar ); // This compiles
foo( 3 ); // This doesn't

Make it a const
void foo( const int& i ) (...)
and they both compile now.

Hope this helps.

Cheers,
Dan

Thanks mate, that was an excellent explanation. subtle but obvious...

Cheers, Mike

This question has already been answered. Start a new discussion instead.