重载导致重复定义
Overload cout results in duplicate definition
我试图在ostream
-类上重载<<
操作符?
由于某种原因,我重载了它两次,我似乎不知道为什么,因为我在我的头文件中有#ifndef
。
matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <iostream>
using namespace std;
class matrix {
int x, y;
public:
matrix(int a, int b);
matrix& operator* (matrix B);
friend ostream& operator<< (ostream& os, const matrix& A);
};
ostream& operator<< (ostream& os, const matrix& A)
{
os << "Matrix.....";
return os;
}
#endif
matrix.cpp
#include <iostream>
#include "matrix.h"
matrix::matrix(int a, int b) {
}
matrix& matrix::operator* (matrix B) {
}
和 main.cpp
#include <iostream>
#include "matrix.h"
using namespace std;
int main () {
matrix a(6, 6), b(6, 6);
cout << a;
return 0;
}
我是这样建的:
$ cat build.sh
g++ -c main.cpp
g++ -c matrix.cpp
g++ -g -o main main.o matrix.o
我得到的构建错误是:
$bash build.sh
ld: duplicate symbol operator<<(std::basic_ostream<char, std::char_traits<char> >&, matrix const&)in matrix.o and main.o for architecture x86_64
collect2: ld returned 1 exit status
我觉得这很困难,但我似乎找不到解决办法。
感谢您的宝贵时间。
g++ - v
$g++ -v
...skipped 4 lines...
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)
您定义了一个带有外部链接的函数,并将其包含在两个编译单元中。
我建议在函数定义中添加一个inline
关键字,或者将函数定义移动到类中。
这是做什么的?
通过添加像operator<<
这样的非static
自由函数,您定义了一个具有外部链接的函数,这意味着它会在生成的目标文件的符号表中产生一个条目。
如果函数是inline
或template
,编译器/链接器必须通过简单地选择任意一个来处理它。(这是可以的,因为ODR使它们相等。)
然而,如果不是这种情况(如在您的示例中),这将导致链接器错误,因为链接器不知道您指的是哪个。
您还可以(甚至额外地)声明您的函数为static
,这将导致它失去外部链接(而获得内部链接),这只是说它不生成符号表项的一种奇特方式。这将导致该函数被编译为包含头文件的每个编译单元的新版本,因此不如其他解决方案。
但是定义守卫呢?
只防止函数在一个编译单元中定义多次。
好,列出我所有的选项!
首先,可以利用友元函数的属性并在类中定义它(这有效地使它获得c++ 11.3/7中定义的inline
关键字):
class matrix {
int x, y;
public:
matrix(int a, int b);
matrix& operator* (matrix B);
friend ostream& operator<< (ostream& os, const matrix& A)
{
os << "Matrix.....";
return os;
}
};
或者,您可以通过在其前面添加inline
使其成为inline
函数。
有时您可能会看到这两种技术结合在一起:友元函数定义在类内部,也用inline
注释。在这种情况下,inline
是完全多余的,不会改变任何东西。
还可以通过向其添加static
关键字或将其包装在未命名的名称空间中来使其获得内部链接。虽然这可以解决问题,但它会导致不必要的膨胀,因为包含该函数的每个编译单元都有自己的内部副本。从技术上讲,内部链接可以与inline
结合使用。
尝试从这个中创建一个模板函数,虽然在技术上是可能的,但需要做很多工作,并且并没有真正获得比其他解决方案更好的东西。但是,它将解决您的问题,导致非常类似于inline
版本的变体。
作为最后一个选项,您可以将函数定义移动到单个编译单元中(读取:.cpp文件)。cpp文件当然是自愿的,因为它包含与matrix
类相关的函数。
- 不同翻译单元中不可重载的非内联函数定义
- 在运算符重载定义中使用成员函数(const错误)
- 重载虚拟行为是否定义良好?
- 为私有结构定义双参数运算符重载
- C++:对函子重载调用运算符的未定义引用
- 指向重载静态成员的函数指针 - 在unique_ptr中用作自定义删除器
- 自定义运算符重载C++,无开销
- 运算符重载以显示用户定义的数据类型
- std::begin-类型特征中未考虑用户定义的重载
- 在priority_queue的自定义类中重载比较运算符
- 重载C++中的[]运算符以支持自定义设置函数
- 运算符的歧义错误<<自定义 std::ostream 子类中的重载
- 重载自定义类型的 std::to_string 和 std::to_chars?
- 当模板重载可用时,检查是否存在函数的自定义重载
- 定义重载C++函数模板的原型时,使用其名称引用以前的定义是否合法?
- 自定义重载运算符<<带有 log4cxx
- 为两个类定义重载的强制转换运算符,这两个类之间具有循环依赖关系
- 在类外部定义重载流出操作符
- 带有std::chrono::duration的用户定义重载操作符*
- 使用C++数组输入定义重载函数是安全的