C++类外实现operator<<时链接报错找不到ns::operator<<如何解决?
问题根因
你在ns命名空间内部的test类中声明的友元operator<<,在没有提前全局前置声明的前提下,默认归属ns命名空间。但你在test.cc中实现该运算符时,将其定义在了全局命名空间,二者是完全独立的两个函数,因此链接器找不到ns::operator<<的实现,报未定义引用错误。
修复方案
方案1:将运算符实现放到ns命名空间下(最常用)
修改test.cc的代码,将实现包裹在ns命名空间中即可:
#include "./test.hh" namespace ns { std::ostream& operator<<(std::ostream& os, const test& a) { os << a.d; return os; } }
方案2:实现时显式指定命名空间全限定名
如果不想包裹命名空间块,也可以在函数名前加全限定名,明确该实现是ns命名空间下的函数:
#include "./test.hh" std::ostream& ::ns::operator<<(std::ostream& os, const ns::test& a) { os << a.d; return os; }
方案3:将运算符定义在全局命名空间
如果确实需要该运算符属于全局作用域,需要修改头文件,提前做全局前置声明,友元声明时显式指定是全局函数:
#pragma once #include <iostream> // 前置声明ns命名空间下的test类 namespace ns { struct test; } // 全局作用域下先声明运算符函数 std::ostream& operator<<(std::ostream&, const ns::test&); namespace ns { struct test { double d; test(double x): d(x) {} // 友元声明加::前缀,指明是全局作用域下的函数 friend std::ostream& ::operator<<(std::ostream&, const test&); }; }
此时你原本写在test.cc的全局实现就可以正常链接。
补充:头文件内联实现
你提到的其他案例将实现写在头文件中,通常是直接将运算符实现为类内的友元函数,或者头文件中加inline修饰实现,这种写法所有编译单元都能看到实现,也不会出现链接错误:
// test.hh 类内实现示例 namespace ns { struct test { double d; test(double x): d(x) {} friend std::ostream& operator<<(std::ostream& os, const test& a) { os << a.d; return os; } }; }
内容的提问来源于stack exchange,提问作者Andrew.Wolphoe
相关产品推荐
相关产品推荐

