2

我试图重载- 类<<上的运算符ostream

出于某种原因,我重载了两次,我似乎无法弄清楚为什么#ifndef我的头文件中有原因。

矩阵.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

矩阵.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)
4

1 回答 1

10

您正在定义一个具有外部链接的函数并将其包含在两个编译单元中。

我建议只inline在你的函数定义中添加一个关键字,或者在类中移动函数定义。

这是做什么的?

通过添加像您这样的非static自由函数,您operator<<可以定义一个具有外部链接的函数,这意味着它会在生成的目标文件的符号表中产生一个条目。

如果函数是inlineor template,编译器/链接器必须处理这个,例如通过简单地选择一个任意的。(这没关系,因为ODR使它们相等。)

但是,如果不是这种情况(如您的示例),则会导致链接器错误,因为链接器不知道您的意思是哪个。

您还可以(甚至另外)将您的函数声明为static,这将导致它失去外部链接(而不是获得内部链接),这只是说它不生成符号表条目的一种奇特方式。这将导致该函数被编译为包含您的头文件的每个编译单元的新版本,因此不如其他解决方案。

但是定义后卫?

只防止函数在一个编译单元中被多次定义。

好的,列出我所有的选项!

首先,您可以利用友元函数的属性并在类中定义它(这有效地使其获得inlineC++ 11.3/7 中定义的关键字):

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 文件)。matrix.cpp 文件当然是自愿的,因为它matrix无论如何都包含与您的课程相关的功能。

于 2013-05-15T17:50:03.173 回答