C ++中的运算符重载编译错误

Posted

技术标签:

【中文标题】C ++中的运算符重载编译错误【英文标题】:Operator overloading compile error in C++ 【发布时间】:2014-03-21 23:21:38 【问题描述】:

我正在尝试制作一个程序来模拟在 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;

每当我尝试编译它时,它都会给我:

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]â

显然还没有非常有经验的课程。完全没有。

【问题讨论】:

【参考方案1】:

您将operator &lt;&lt; 声明为成员函数

Ship operator<<(const Ship&);

表示左操作数是 Ship 类的一个实例。所以它可以被称为

Ship a, b;

a << b;

但很明显你不想要这个。

如果你想在输出流中输出一个 Ship 类的对象,那么操作符必须是一个非成员函数。 您可以将其定义为类的友元函数。例如

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
;

然后您可以将其定义为例如以下方式

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;

由于坐标数是固定的,所以不需要使用std::vector。改用std::array&lt;std::pair&lt;int, int&gt;, 4&gt;

同时删除语句

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

来自构造函数。它是一个局部变量。您需要填写数据成员 ship_loc 而不是这个局部变量。

【讨论】:

我做了'朋友'功能,结合@AndyG的最后评论。我编译得很好(哇哦!)但是当我运行它时,我得到了一个分段错误。我已经读到这通常是由于试图访问我不允许访问的一段内存,或者至少不允许使用我正在尝试做的事情。我希望它能给我一些关于错误来自哪里的线索。有什么想法吗? @UnworthyToast 查看我更新的帖子。【参考方案2】:

以下行不符合您的预期:

  Ship operator<<(const Ship&);

当您重载&lt;&lt; 运算符时,您不能返回Ship,并且第一个参数必须是ostream 类型。它的返回类型必须是std::ostream&amp;。引用此线程的答案之一:C++ Operator Overloading

在最常见的重载运算符中,流运算符是二进制中缀运算符,其语法没有指定它们应该是成员还是非成员。由于它们改变了左参数(它们改变了流的状态),根据经验法则,它们应该被实现为左操作数类型的成员。 但是,它们的左操作数是来自标准库的流,虽然标准库定义的大多数流输出和输入操作符确实定义为流类的成员,但当您自己实现输出和输入操作时类型,您不能更改标准库的流类型。这就是为什么您需要为自己的类型实现这些运算符作为非成员函数。

一种方法是使用规范形式来实现它:

std::ostream& operator<<(std::ostream& os, const Ship& obj)

    // write obj information
    return os;
 

【讨论】:

我怎样才能让我的重载操作员能够使用ship_loc?我在想,因为我在构造函数中定义它之前在类中声明了ship_loc,所以它可以被类中的任何东西使用,但显然不是。 @UnworthyToast:ship_locShip的成员,所以你可以使用taocp的功能说obj.ship_loc[0]等等。 @AndyG 当我使用您在运算符中描述的方法执行std::cout &lt;&lt; first_ship &lt;&lt; std::endl; 时,它给了我:error: cannot bind âstd::ostream aka std::basic_ostream&lt;char&gt;â lvalue to âstd::basic_ostream&lt;char&gt;&amp;&amp;â 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&lt;_CharT, _Traits&gt;&amp; std::operator&lt;&lt;(std::basic_ostream&lt;_CharT, _Traits&gt;&amp;&amp;, const _Tp&amp;) [with _CharT = char; _Traits = std::char_traits&lt;char&gt;; _Tp = std::pair&lt;int, int&gt;]â @UnworthyToast:对不起,我没有意识到ship_loc[0]pair&lt;int, int&gt;类型,所以你必须说ship_loc[0].first &lt;&lt; ", " &lt;&lt; ship_loc[0].second "错误在这里" - 这不是错误,它重载了&lt;&lt; 运算符,将Ship 作为两个操作数并返回Ship。没关系。运营商&lt;&lt; 在人们想到 iostream 之前就已经存在了很长时间。他的错误出现在文件的后面。 (他当然不打算这样做,但这是合法的)。【参考方案3】:

你错误地重载了operator&lt;&lt;,你想要的签名是这样的:

std::ostream& operator<<(std::ostream& os, const Ship& s);

【讨论】:

以上是关于C ++中的运算符重载编译错误的主要内容,如果未能解决你的问题,请参考以下文章

重载运算符的 C++ 前向声明

枚举类中的 c++ 运算符重载

c++中加号运算符重载

不能重载 Raku 中的 >> 运算符

C/C++编程笔记:C++中的运算符重载

JAVA怎样重载操作符?