c – 未定义的对运算符<<的引用

前端之家收集整理的这篇文章主要介绍了c – 未定义的对运算符<<的引用前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个普通课(不是一个模板,就是这样),一个私人的朋友运算符<< 它的声明是:
std::ostream& operator<<(std::ostream& out,const Position& position);

在cpp文件中,它的定义是:

std::ostream& operator<<(std::ostream& out,const Position& position)
{
  out << position.getXPoint() << "," << position.getYPoint();
  return out;
}

它正在被编译,然后链接到使用它的主要功能,但是当我使用它,我得到一个未定义的引用…

然而,当我将定义添加到主cpp文件的顶部并删除朋友声明时,它工作正常…

我在我的主要功能中使用它

std::cout << node->getPosition() << std::endl;

不多不少…

遇到链接错误

/home/luke/Desktop/pathfinder/parse_world.cpp:34: undefined reference to `pathfinder::operator<<(std::ostream&,pathfinder::Position const&)’

并且继承类头

#ifndef PATHFINDER_H
#define PATHFINDER_H
#include <ostream>
#include <istream>
#include <list>
#include <vector>
#include <stdexcept>
#include <cstring>
namespace pathfinder
{
class Node;
typedef unsigned int GCost;
typedef std::vector<std::vector<Node*> > World;
typedef std::vector<Node*> WorldRow;
class Position
{
public:
    typedef unsigned int point_type;
private:
    point_type* xPoint_;
    point_type* yPoint_;
    friend std::ostream& operator<<(std::ostream& out,const Position& position);
public:
    Position(const point_type& xPoint = 0,const point_type& yPoint = 0);
    Position(const Position& position);
    Position(Position&& position);
    ~Position();

    Position& operator=(const Position& position);
    Position& operator=(Position&& position);

    point_type getXPoint() const;
    point_type getYPoint() const;

    void setXPoint(const point_type& xPoint);
    void setYPoint(const point_type& yPoint);
};
class Node
{
private:
    bool* isPassable_;
    bool* isStartingNode_;
    bool* isTargetNode_;
    Position* position_;
    GCost* additionalGCost_;
    Node* parent_;
public:
    Node(const bool& isPassable = true,const bool& isStartingNode = false,const bool& isTargetNode = false,const Position& position = Position(0,0),const GCost& additionalGCost = 0,Node* parent = nullptr);
    Node(const Node& node);
    Node(Node&& node);
    ~Node();

    Node& operator=(const Node& node);
    Node& operator=(Node&& node);

    bool isPassable() const;
    bool isStartingNode() const;
    bool isTargetNode() const;
    Position getPosition() const;
    GCost getAdditionalGCost() const;
    Node* getParent() const;

    void setAsPassable(const bool& isPassable);
    void setAsStartingNode(const bool& isStartingNode);
    void setAsTargetNode(const bool& isTargetNode);
    void setPosition(const Position& position);
    void setAdditionalGCost(const GCost& additionalGCost);
    void setParent(Node* parent);
};
class WorldHelper
{
public:
    static World fromStream(std::istream& input);
    static void syncPositions(World& world);
    static void uninitializeWorld(World& world);
    static Node* findStartingNode(const World& world);
    static Node* findTargetNode(const World& world);
};
class Pathfinder
{
public:
    virtual std::list<Node*> operator()(World& world) const = 0;
};
};
#endif //PATHFINDER_H

现在删除好友声明后,我收到错误信息,如:

cannot bind ‘std::ostream {aka std::basic_ostream}’ lvalue to ‘std::basic_ostream&&’

它发生在与std :: cout语句相同的行上…

那么什么交易…

提前致谢

解决方法

我的猜想是,从描述中你宣告两个操作符<但只定义一个.例如:
namespace A {
   struct B {
      friend std::ostream& operator<<( std::ostream&,B const & ); // [1]
   };
}
std::ostream& operator<<( std::ostream& o,A::B const & ) {        // [2]
   return o;
}

行[1]声明一个A ::运算符<<函数可以通过类型B上的ADL找到,但是[2]声明并定义了:: operator<<<.当编译器看到代码时:

A::B b;
std::cout << b;

它使用ADL并找到A :: operator<< (来自朋友声明)并使用它,但该功能未定义.如果你删除了这个朋友的声明,那么就有一个运算符<<在全局命名空间中声明和定义,并通过定期查找找到它. 还要注意,如果在程序中使用指令,这可能更难发现,因为[2]中的定义可能不会为参数显式命名A命名空间.这也可以解释你可以定义类型的其余成员:

// cpp [assume that the definition of B contained a member f
using namespace A;
void B::f() {
}

B :: f的定义驻留在全局命名空间中(代码中),但是由于using指令,B将在A命名空间中找到,并且类型说明符将等价于A :: B,使定义等同于void :: A :: B :: f(){}解析B.这不会发生免费函数.

我建议您避免使用指令,因为它们允许这样的微妙错误.另外请注意,您可以明确地定义命名空间中的运算符(但是您还需要在命名空间中声明它:

namespace A {
   struct B  { friend std::ostream& operator<<( std::ostream&,B const & ); };
   std::ostream& operator<<( std::ostream&,B const & );
}
std::ostream& A::operator<<( std::ostream& o,B const & ) {
   return o;
}

这个技巧(通过完全限定)在自然命名空间之外定义自由函数)有时用于避免定义隐式声明它的函数,这很容易出现这种类型的错误.例如,如果您在正确的命名空间中定义了运算符,但签名略有不同:

namespace A {
   struct B  {
      friend std::ostream& operator<<( std::ostream&,B const & ); // [1]
   };
   std::ostream& operator<<( std::ostream&,B & ) {                // [3]
      return o;
   }
}

[3]中的定义也是一个声明,但它声明一个与[1]中声明的函数不同的函数,您可能会最终抓住头,问为什么链接器没有找到[1].

猜你在找的C&C++相关文章