我想重载<<-类上的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<<自由函数,您可以定义具有外部链接的函数,这意味着它将在生成的目标文件的符号表中产生一个条目。

如果函数是inlinetemplate,则编译器/链接器必须处理此问题,例如只需选择任意一个即可。 (这是可以的,因为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/

10-11 22:47
查看更多