Question

I am trying to make a program to simulate playing Battleship in C++

#include <iostream>
#include <vector>

class Ship {
public:
    Ship();
    Ship operator<<(const Ship&);
private:
    int x = 0;
    int y = 0;
    std::vector<std::pair<int, int>> ship_loc;      //Ship location
};

Ship::Ship() {
    srand(time(NULL));
    std::vector<std::pair<int, int>> ship_loc;      //Ship location
    for (int i = 0; i < 4; ++i) {
            x = rand() % 20;
            y = rand() % 20;
            std::pair<int, int> coordinates = std::make_pair(x, y);
            ship_loc.push_back(coordinates);
            //ship_loc.push_back(std::pair<x, y>)
    };
};

Ship operator<<(const Ship &s) {
    std::cout << ship_loc[0] << ship_loc[1] << ship_loc[2] << ship_loc[3]
            << std::endl;
}

int main()
{
    Ship first_ship;
    std::cout << first_ship;
}

Whenever I try to compile this it give me:

battleship.cpp:26:30: error: âShip operator<<(const Ship&)â must take exactly two           arguments
battleship.cpp: In function âint main()â:
battleship.cpp:34:25: error: cannot bind âstd::ostream {aka std::basic_ostream<char>}â     lvalue to âstd::basic_ostream<char>&&â
In file included from /usr/include/c++/4.7/iostream:40:0,
             from battleship.cpp:1:
/usr/include/c++/4.7/ostream:600:5: error:   initializing argument 1 of     âstd::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&,     const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = Ship]â

Obviously not very experienced with classes yet. At all.

Was it helpful?

Solution

You declared operator << as a member function

Ship operator<<(const Ship&);

It means that the left operand is an instance of class Ship. So it could be called as

Ship a, b;

a << b;

But it is obvious that you did not want this.

if you want to output an object of class Ship in output stream then the operator has to be a non-member function. You could define it as a friend function of the class. for example

class Ship {
public:
    Ship();
    friend std::ostream & operator <<( std::ostream &os, const Ship& );
private:
    int x = 0;
    int y = 0;
    std::vector<std::pair<int, int>> ship_loc;      //Ship location
};

And then you could define it as for example the following way

std::ostream & operator <<( std::ostream &os, const Ship &s) 
{
    os << "( " << s.ship_loc[0].first << ", " << s.ship_loc[0].second << " )" 
       << ", ( " << s.ship_loc[1].first << ", " << s.ship_loc[1].second << " )"
       << ", ( " << <.ship_loc[2].first << ", " << s.ship_loc[3].second << " ) "
       << ", ( " << <.ship_loc[3].first << ", " << s.ship_loc[3].second << " ) "
       << std::endl;

   return os;
}

Also as the number of coordinates is fixed then there is no need to use std::vector. Use instead std::array<std::pair<int, int>, 4>

Also remove statement

std::vector<std::pair<int, int>> ship_loc;      //Ship location

from the constructor. It is a local variable. You need to fill data member ship_loc instead of this local variable.

OTHER TIPS

The following line does not do what you intend to be:

  Ship operator<<(const Ship&);

You cannot return Ship and the first parameter has to be of ostream type when you overload the << operator. Its return type has to be std::ostream&.Quoting from one of the answers from this thread: C++ Operator Overloading

The stream operators, among the most commonly overloaded operators, are binary infix operators for which the syntax specifies no restriction on whether they should be members or non-members. Since they change their left argument (they alter the stream’s state), they should, according to the rules of thumb, be implemented as members of their left operand’s type. However, their left operands are streams from the standard library, and while most of the stream output and input operators defined by the standard library are indeed defined as members of the stream classes, when you implement output and input operations for your own types, you cannot change the standard library’s stream types. That’s why you need to implement these operators for your own types as non-member functions.

One way is to implement it with the canonical form:

std::ostream& operator<<(std::ostream& os, const Ship& obj)
{
    // write obj information
    return os;
 }

You're overloading operator<< incorrectly, the signature you want is something like:

std::ostream& operator<<(std::ostream& os, const Ship& s);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top