我想重载<<
-类上的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
关键字,或在类内移动函数定义。
这是做什么的?
通过添加类似于static
的非operator<<
自由函数,您可以定义具有外部链接的函数,这意味着它将在生成的目标文件的符号表中产生一个条目。
如果函数是inline
或template
,则编译器/链接器必须处理此问题,例如只需选择任意一个即可。 (这是可以的,因为ODR使它们等效。)
但是,如果不是这种情况(如您的示例所示),则会导致链接器错误,因为链接器不知道您的意思是哪个。
您还可以(或什至另外)将您的函数声明为static
,这将导致它失去外部链接(取而代之的是获得内部链接),这只是一种说法,它不生成符号表条目。这将导致此函数针对包含您的 header 的每个编译单元被编译为新版本,因此不如其他解决方案。
但是定义后卫?
仅防止在一个编译单元中多次定义函数。
好,列出所有选项!
首先,您可以利用好友函数的属性并在类中对其进行定义(这实际上使它获得了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
关键字或将其包装在unnamed namespace中来使其内部链接。虽然这可以解决问题,但会引起不必要的膨胀,因为每个包含此功能的编译单元都会有自己的内部副本。从技术上讲,内部链接可以与inline
结合使用。在技术上可行的情况下,尝试从中实现模板功能是一项繁重的工作,并且在其他解决方案之上并没有真正让您受益。但是,这将解决您的问题,从而导致类似于
inline
版本的变体。作为最后一个选择,您可以将函数定义移动到单个编译单元中(阅读:.cpp文件)。 matrix.cpp文件肯定是自愿的,因为它仍然具有与
matrix
类有关的功能。关于c++ - 重载指令导致重复定义,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16571730/