3

我正在尝试重载流运算符 <<,对于已经具有 toString()返回字符串的函数的类 Foo,使用以下代码:

std::ostream &operator<<( std::ostream &flux, Foo const& foo )
{
    flux <<  foo.toString(); 
    return flux;
}

为了在main.cpp文件中使用它

我的问题是:把那段代码放在哪里?

  • 如果我把它放在main.cpp, 在它使用之前,它工作得很好,但我可能想在其他文件中使用它。
  • 如果我将它放在 中foo.cpp,我会收到“没有这样的功能”错误:

    src/main.cpp:77: error: no match for ‘operator<<’ in ‘std::cout << foo’
    

    这是有道理的,因为代码不包含在main.cpp文件中

  • 如果我把它放在foo.h类头中,在类声明之外,我会得到一个“多重定义”错误:

    foo.o: In function `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Foo const&)':
    foo.cpp:(.text+0x0): multiple definition of `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Matrix const&)'
    bar.o:bar.cpp:(.text+0x0): first defined here
    

    foo.h头确实包含在不同的类/文件中,但是有一个 ifdef 保护,所以我不明白这一点。

那我该怎么办?

4

5 回答 5

11

有多种选择:

在标头中声明它,在 之后Foo,并在 中定义它Foo.cpp

//foo.h
class Foo
{};
std::ostream &operator<<( std::ostream &s, Foo const& foo );

//foo.cpp
#include "foo.h"
std::ostream &operator<<( std::ostream &s, Foo const& foo )
{
    return s;
}

将其定义为friend类定义内部。

//Foo.h
class Foo
{
   friend std::ostream &operator<<( std::ostream &s, Foo const& foo )
   {
      return s;
   }
};

定义在头部,在类定义之外,并标记为inline防止多重定义。

//Foo.h
class Foo
{
};

inline std::ostream &operator<<( std::ostream &s, Foo const& foo )
{
   return s;
}
于 2012-11-22T16:28:15.477 回答
4

将重载的原型放在类声明中,将其实现放在Foo实现处(或者如果你想要它inline,把它放在Foo声明处)。

所以要么:

// foo.h
#ifndef FOO_H_ASDSADKJSLADJL
#define FOO_H_ASDSADKJSLADJL
class Foo {
};
std::ostream& operator<< (std::ostream &, Foo const &);
#endif // FOO_H_ASDSADKJSLADJL

// foo.cpp
#include "foo.h"
....
std::ostream& operator<< (std::ostream &os, Foo const &) {
    ....
    return os;
}

或者

#ifndef FOO_H_ASDSADKJSLADJL
#define FOO_H_ASDSADKJSLADJL
class Foo {
};
inline std::ostream& operator<< (std::ostream &os, Foo const &) {
    ....
    return os;
}
#endif // FOO_H_ASDSADKJSLADJL

您的编译器没有找到它的错误是缺少重载原型。

于 2012-11-22T16:26:03.327 回答
4

将声明放在头文件中,将定义放在 cpp 文件中。

也就是说,放

std::ostream &operator<<( std::ostream &flux, Foo const& foo );

在你的头文件中,并把

std::ostream &operator<<( std::ostream &flux, Foo const& foo )
{
    flux <<  foo.toString(); 
    return flux;
}

在你的 cpp 文件中。

这样,你可以在任何你想要的地方包含头文件,并且可以使用该函数,但它只会被定义一次,所以你不会得到multiple definitions错误。

于 2012-11-22T16:26:33.747 回答
0

在标头中声明它,在哪里声明Foo,在源代码中定义它,在哪里定义Foo方法。

于 2012-11-22T16:27:22.787 回答
0

与 C 和 C++ 一样,您应该

  1. 将实际代码放入适当的.c/.cpp文件中 - 我建议在这里foo.cpp
  2. 预先声明放入适当的.h/头文件中,并对从主 c/cpp 文件外部使用的所有内容.hpp进行适当的保护。#ifdef

在某些情况下,您可以使用#define宏或inline函数。这应该在标题中完成;由于内联,不应该有多重声明错误。

从技术上讲,您可以做很多事情。我建议坚持在头文件中定义 API 并将实现放入代码文件中的最佳实践。这是最可扩展的。该inlinehack 将适用于这种情况,但如果您稍后决定增强该方法并删除内联,它会令人惊讶地中断。

标头/代码拆分最不可能中断。

于 2012-11-22T16:29:13.767 回答