2012-03-23 46 views
2

我在指针上调用operator<<时遇到问题。我已经通过搜索并在Google上提出了我的问题,但所有提出的解决方案都无法解决我的问题。为了说明我的问题,请参见简化一块我的代码:已重载的std :: ostream运算符<<未调用,流获取变量地址而不是对象

Marker.h

class Marker { 
    ... 
public: 
    friend std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    friend std::ostream& operator<<(std::ostream& out, Marker* marker); 
}; 

inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { 
     out << "Marker " << marker._name << " of type " << marker._type << " at position " << marker._position; 
     return out; 
} 

inline std::ostream& operator<<(std::ostream& out, Marker* marker) { 
     out << *marker; 
     return out; 
} 

Landmark.h

class Landmark { 
     ... 
     Marker* m_marker; 
     ... 
}; 

Landmark.cpp

void Landmark::print(std::ostream& out) 
{ 
    out << "Marker GENERIC: " << m_marker << std::endl; 
    //out << "Marker GENERIC: " << *m_marker << std::endl; 
} 

这不会在Visual Studio 2008下链接。我得到一个unresolved external symbol错误的负载。如果我删除friend std::ostream& operator<<(std::ostream& out, Marker* marker);,代码编译,但不是预期的格式化输出,我只获得指向标记Marker* Landmark::m_marker的指针的内存地址。取消注释第二行将我的代码变成无法解读的代码。

我应该如何重载operator<<以便我得到正确的输出?

我将不胜感激任何帮助!

+0

注:为指针过载,两件事情失踪。它应该读取'Marker const * marker',因为'Marker'实例没有任何突变;它应该测试无效,以防万一,在这种情况下可能输出''。 – 2012-03-23 15:29:16

+0

如果您尝试在其自己的编译单元(即在.cpp文件中)中定义'std :: ostream&operator <<(std :: ostream&out,Marker * marker)'作为(非内联)函数,这使链接器开心? – 2012-03-23 14:34:18

+0

然后编译器并不争论,但包含此DLL的项目无法编译:函数std :: ostream&operator <<(std :: ostream&out,Marker * marker)上的'unresolved external symbol''。这个函数是否应该在全局命名空间中定义?就我而言,我所有的类和重载的运算符函数都位于我的名字空间内。 – 2012-03-23 14:45:29

回答

2

下面是一个简单的例子:

#include <iostream> 

namespace mine { 
class Marker { 
public: 
    friend std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    friend std::ostream& operator<<(std::ostream& out, Marker* marker); 
}; 

inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { 
    out << "Marker"; 
    return out; 
} 

inline std::ostream& operator<<(std::ostream& out, Marker* marker) { 
    out << *marker; 
    return out; 
} 
} // namespace mine 

int main() { 
    mine::Marker marker; 
    mine::Marker* m = &marker; 

    std::cout << m << "\n"; 
} 

和它的作品as expected

您指向的错误是链接器错误,它告诉您编译器向未发出函数的方法发出调用。

我会假设你对我们说谎或者Visual Studio再次出错。

  • 如果你骗(即不复制确切的代码):注意definining的inline方法时,整个身体的方法应包括使用前,因此Landmark.cpp应包括方法的定义。
  • 或者,可能需要通过在加入VS之前预先声明函数来帮助VS,以便VS知道它们确实存在于mine命名空间中,而不是位于全局命名空间中。

喜欢的东西:

namespace mine { 
    class Marker; 

    std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    std::ostream& operator<<(std::ostream& out, Marker* marker); 

    class Marker { 
    public: 
    friend std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    friend std::ostream& operator<<(std::ostream& out, Marker* marker); 
    }; 

    inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { 
    out << "Marker"; 
    return out; 
    } 

    inline std::ostream& operator<<(std::ostream& out, Marker* marker) { 
    out << *marker; 
    return out; 
    } 
} // namespace mine 
+0

感谢您的广泛答复!向编译器解释函数在本地名称空间中的第二个技巧已经奏效。问题可能在于我称operator <<关于operator <<内的另一个对象,并且同样的错误发生了两次,所以很难追踪它。 – 2012-03-26 06:38:25

+0

@PavloDyban:我有VS2003的这个bug(如果内存服务正确),它与“递归”无关。通常'friend'声明应该引入在类的名字空间中声明的函数,但似乎如果没有先前的声明存在,VS会绊倒它。我不确定这是不是标准指定的(我希望它是一个错误)。 – 2012-03-26 07:16:11

0

更改此

friend std::ostream& operator<<(std::ostream& out, Marker* marker); 

对此

friend std::ostream& operator<<(std::ostream& out, Marker marker); 

然后用这个

out << "Marker GENERIC: " << *m_marker << std::endl; 

你的输出操作期待一个指针,而你正在通过实际的对象。

+1

根据Marker的实现方式,按值传递它可能不是一个好主意 - 可能更好地将第二个参数设置为流操作符const marker&marker而不是“Marker marker”。 – 2012-03-23 14:32:20

+0

谢谢您的评论!我用指针隐藏了重载作为参数,而是使用了引用指针。这与您通过按值传递标记所提出的几乎相同。但是,我希望我在'out <<“标记GENERIC:”<< * m_marker << std :: endl;''一行中没有星号。我应该如何重载我的操作符来获取指向'Marker'的指针并输出对象的内容? – 2012-03-23 14:51:38

1

现在,你有重载采取指针和对象的引用。你传递一个指针,所以引用的重载将不会被使用。

你想反过来:摆脱需要一个指针的重载,并使用需要引用的重载。通过取消引用指针使用它:out << *m_marker;

+0

谢谢!你给了我一个正确的建议!现在,如果我仍然想离开'out <<“标记GENERIC:”<< m_marker << std :: endl;',即通过传递标记对象的地址,我应该如何重载'operator <<' ? – 2012-03-23 14:49:10

相关问题