重载cout会导致重复定义

and*_*lrc 2 c++ iostream operator-overloading

我试图<<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
Run Code Online (Sandbox Code Playgroud)

matrix.cpp

#include <iostream>
#include "matrix.h"

matrix::matrix(int a, int b) {

}
matrix& matrix::operator* (matrix B) {

}
Run Code Online (Sandbox Code Playgroud)

main.cpp

#include <iostream>
#include "matrix.h"

using namespace std;

int main () {
    matrix a(6, 6), b(6, 6);

    cout << a;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我是这样建造的:

$ cat build.sh 
g++ -c main.cpp
g++ -c matrix.cpp

g++ -g -o main main.o matrix.o
Run Code Online (Sandbox Code Playgroud)

我得到的构建错误是:

$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
Run Code Online (Sandbox Code Playgroud)

认为这是一个前沿,但我似乎无法找到解决方案.

谢谢你的时间.


g ++ -v

$g++ -v
...skipped 4 lines...
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)
Run Code Online (Sandbox Code Playgroud)

gha*_*.st 9

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

我主张只inline在函数定义中添加一个关键字,或者在类中移动函数定义.

这是做什么的?

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

如果函数是inlinetemplate,则编译器/链接器必须处理此问题,例如通过简单地选择任意一个.(这没关系,因为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;
    }
};
Run Code Online (Sandbox Code Playgroud)

或者,你可以inline通过inline在它前面添加它来使它成为一个函数.

您有时可能会看到这两种技术相结合:在类中定义并使用注释的友元函数inline.该inline是在这种情况下完全是多余的,并不会改变任何东西.

您也可以通过向其添加static关键字或将其包装在未命名命名空间中来使其获得内部链接.虽然这可以解决问题,但它会导致不必要的膨胀,因为包含此函数的每个编译单元都有自己的内部副本.技术上内部联系可以与之结合inline.

在技​​术上可行的情况下,尝试制作模板功能是一项很多工作,并没有真正获得超越其他解决方案的任何东西.但它解决您的问题,导致变体非常类似于inline版本.

作为最后一个选项,您可以将函数定义移动到单个编译单元中(读取:.cpp文件).matrix.cpp文件肯定是志愿者,因为它保留了与你的matrix课程相关的功能.