【问题标题】:Overloaded non-member operator== undefined?重载非成员运算符==未定义?
【发布时间】:2013-01-10 13:44:31
【问题描述】:

g++ 4.5.3 (cygwin)

我在定义重载的非成员运算符== 时遇到了麻烦。编译器输出错误信息

main.cpp:11:未定义对 `slip::operator==(bool, slip::SlipDatum const&) 的引用

我不知道我做错了什么。在我看来,所有的定义都是可见的,所有的函数原型和代码都是正确的。当重载用作成员函数时,如“(SlipDatum&)Y == (bool)X”,没有问题。作为一个非成员函数,我不断得到一个未定义的引用。

另一个问题是,当从 Slip.cpp 中删除 '#include SlipOp.h"' 时,SlipDatum 在 Slip.cpp 中未定义。我查看了 SlipDatum.h 并且不需要 SlipOp.h。我已经看了SlipDatum.cpp,需要并包含SlipOp.h。Slip.cpp中不需要或引用SlipOp.h,那为什么编译器会认为需要呢?

使用的示例代码如下:

main.cpp

# include <cstdlib>
# include "Slip.h"
# include <iostream>
using namespace std;
using namespace slip;

int main(int argc, char** argv) {
   SlipDatum Y;
   bool X = true;
   if (X == Y) cout << "here" << endl;
   return 0;
}

滑动.h

#ifndef SLIP_H
#define SLIP_H
# include "SlipDatum.h"

namespace slip {
   bool      operator==(const bool   X, const SlipDatum& Y);  // Y == X
}; // namespace slip
#endif  /* SLIP_H */

滑动.cpp

# include "Slip.h"
# include "SlipCellBase.h"
# include "SlipOP.h"
# include "SlipDatum.h"

inline  bool operator==(const bool X, const SlipDatum& Y) 
     { return const_cast<SlipDatum&>(Y) == X; };

SlipDef.h

#ifndef SLIPDEF_H
#define SLIPDEF_H

# include <string>

using namespace std;

namespace slip {

#ifdef UCHAR
   # undef UCHAR
#endif
#ifdef ULONG
   # undef ULONG
#endif
#ifdef DOUBLE
   # undef DOUBLE
#endif
#ifdef PTR
   # undef PTR
#endif

   typedef unsigned char   UCHAR;               //  8-bits
   typedef unsigned long   ULONG;               // 32-bits
   typedef double          DOUBLE;              // 64-bits
   typedef void *          PTR;                 // pointer
   typedef string *        STRING;              // C String

   union Data {                                 // Slip data contents
       bool      Bool;                          // compiler defined
       char      Chr;                           //  8-bits
       UCHAR     UChr;                          //  8-bits
       long      Long;                          // 32-bits
       ULONG     ULong;                         // 32-bits
       double    Double;                        // 64-bits
       PTR       Ptr;                           // 
       STRING    String;                        // pointer to a string
   }; // union Data
} // namespace slip
#endif  /* SLIPDEF_H */

SlipCellBase.h

#ifndef _SLIPCELLBASE_H
#define _SLIPCELLBASE_H

# include "SlipDef.h"

using namespace std;

namespace slip {
  class SlipCellBase {
     friend class SlipOp;
  private:
      void*         operation;   //! Operations cell can perform
      SlipCellBase* leftLink;    //! Pointer to preceding cell
      SlipCellBase* rightLink;   //! Pointer to following cell
      Data          datum;       //! SLIP cell data field
 protected:
      void** getOperator() const 
           { return &const_cast<SlipCellBase*>(this)->operation; }
      static void** getOperator(SlipCellBase* X) 
           { return   &(X->operation);   }
  }; // class SlipCellBase
}; // namespace slip
#endif  /* SLILPCELLBASE_H */

SlipDatum.h

#ifndef SLIP_DATUM_H
#define SLIP_DATUM_H
# include "SlipCellBase.h"
namespace slip {
  class SlipDatum : public SlipCellBase {
  public:
     bool       operator==(const bool X);  // Y == X
  }; // SlipDatum
}; // namespace slip
#endif

SlipDatum.cpp

# include "SlipDatum.h"
# include "SlipOP.h"
# include "SlipCellBase.h"

bool SlipDatum::operator==(const bool X)
    { return ((SlipOp*)*getOperator())->equal(*this, X); }

SlipOp.h

#ifndef _SLIPOP_H
#define _SLIPOP_H
# include "SlipDatum.h"

using namespace slip;

namespace slip {
  class SlipOp {
  public:
     virtual bool equal(SlipDatum& Y, const bool X)  = 0;
  }; // class SlipOp
}; // namespace slip
#endif  /* _SLIPOP_H */

SlipBool.h

#ifndef _SLIPboolOP_H
#define _SLIPboolOP_H
# include "SlipOp.h"

namespace slip {
  class SlipBoolOp : public SlipOp {
  public:
     virtual bool equal(SlipDatum& Y, const bool   X);
  }; // class SlipBoolOp
}; // namespace slip
#endif  /* SLIPboolOP_H */

SlipBool.cpp

# include "SlipBoolOp.h"
# include "SlipDatum.h"

using namespace slip;

namespace slip {
  bool SlipBoolOp::equal (SlipDatum& Y, const bool X) {
    return false;
  }; // bool SlipBoolOp::equal (SlipDatum& Y, const SlipDatum& X) 

}; // namespace slip

【问题讨论】:

  • tl;dr 但您几乎肯定想从Slip.cppoperator== 的定义中删除inline。除此之外可能还有其他问题。哦,是的,如果您要定义在头文件中声明的相同函数,您可能希望将定义放在 slip 命名空间中。

标签: c++ operator-overloading


【解决方案1】:

在 slip.cpp 中,您在全局范围内定义 operator==,即您错过了命名空间:

namespace slip {
  bool operator==(bool X, const SlipDatum& Y) 
  { return const_cast<SlipDatum&>(Y) == X; };
}

PS: const_cast 应该不是必需的,因为operator==(SlipDatum&amp;, bool) 也应该通过 const 引用获取 SlipDatum。即在 slipdatum.h/cpp 中:

namespace slip {
  class SlipDatum : public SlipCellBase {
  public:
     bool       operator==(bool X) const; // <--! *this is left constant                                          
  }; 
};

【讨论】:

  • +1,或者,在全局命名空间中:bool slip::operator==(bool X, const slip::SlipDatum&amp; Y) ...。第一个参数中的 const 具有误导性(它将从声明中删除)。在命名空间之外定义函数但具有限定的优点是它禁止自我声明(即,如果你弄错命名空间,编译器会叫喊,而不是链接器)。
  • 我进行了更改(如下),错误消息现在显示来自 main 的引用未定义(未定义对 `slip::operator==(bool, slip::SlipDatum const&) 的引用)。所做的更改是在 slip.cpp 中添加命名空间并删除 const_cast,将 SlipDatum.h 中的原型更改为 const,将 const SlipDatum& 添加到 SlipOP.h 中的原型(需要删除错误),将命名空间添加到 SlipDatum.cpp。当我添加 slip::operator==(X,Y) - 以符合错误消息时 - 返回错误是 slip::operator==(bool, SlipDatum&) 未定义。不同的错误,同样的挫败感。
  • 该错误表明它正在寻找slip::operator==(bool, SlipDatum&amp;),即第二个参数不是const。这意味着,您要么没有在标头中将该参数设置为 const,要么您没有重新编译包含该标头的所有源,因此一些较旧的目标文件仍然引用非 const 版本。
  • 我心碎了!只需检查 Slip.*。第一个参数非常量。第二个参数 const。但是,当我从 Slip.cpp 中删除“内联”时,它编译正确。现在有趣的是,我在使用“内联”时一直遇到问题。有时编译器会接受它,而在其他情况下我会得到(就像这里一样)和未定义的引用。在头文件或源文件中放置“内联”似乎具有相同的效果。 Slip.* 中显示的代码是实际代码。内联一个 1 行方法会很好。将代码分为 .h 和 .cpp 是定性的。 Drat,编译器咬了我。
  • 忘记内联 - 在大多数情况下。在大多数情况下,这只是对编译器的提示。一方面它可以忽略它,另一方面它可以内联你没有声明内联的函数,就像它认为合适的那样。现代编译器甚至可以进行链接时间优化,跨翻译单元边界内联那些单行代码。今天内联的一个也是唯一的用例是当您在头文件中定义非模板函数,但在类定义之外。然后你需要内联以避免 ODR 违规。
猜你喜欢
  • 1970-01-01
  • 2017-08-03
  • 1970-01-01
  • 2019-03-30
  • 2011-06-05
  • 2013-11-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多