函数的多个定义出现错误

时间:2021-04-26 17:03:21

I am trying to relearn C++ after taking an intro course a few years ago and I’m having some basic problems. My current problem occurs when trying to use a friend function. Here is my code in 2 files.

几年前我参加了一门入门课程,现在我正在努力重新学习c++,我遇到了一些基本的问题。我当前的问题出现在尝试使用friend函数时。这是我的两个文件的代码。

First:

第一:

// fun.cpp

#include <iostream>
using namespace std;

class classA {
    friend void funct();
public:
    classA(int a=1,int b=2):propa(a),propb(b){cout<<"constructor\n";}
private:
    int propa;
    int propb;
    void outfun(){
        cout<<"propa="<<propa<<endl<<"propb="<<propb<<endl;
    }
};
void funct(){                     // ERROR HERE
    cout<<"enter funct"<<endl;
    classA tmp(1,2);
    tmp.outfun();
    cout<<"exit funct"<<endl;
}

Second:

第二:

// mainfile.cpp
#include <iostream>
#include "fun.cpp"
using namespace std;

int main(int nargin,char* varargin[]) {
    cout<<"call funct"<<endl;
    funct();
    cout<<"exit main"<<endl;
    return 0;
}

The error I am getting is "multiple definition of `funct()'". Am I using the wrong syntax when declaring it as a friend function?

我得到的错误是“funct()的多重定义”。在将它声明为friend函数时,我是否使用了错误的语法?

2 个解决方案

#1


44  

Here is a highly simplified but hopefully relevant view of what happens when you build your code in C++.

这里有一个高度简化但希望与用c++构建代码相关的视图。

C++ splits the load of generating machine executable code in following different phases -

c++将生成机器可执行代码的负载分成以下几个阶段

  1. Preprocessing - This is where any macros - #defines etc you might be using get expanded.

    预处理-这是任何宏- #定义等等你可能正在使用的扩展。

  2. Compiling - Each cpp file along with all the #included files in that file directly or indirectly (together called a compilation unit) is converted into machine readable object code.

    编译—每个cpp文件以及该文件中包含的所有#文件(统称为编译单元)都被转换为机器可读的对象代码。

    This is where C++ also checks that all functions defined (i.e. containing a body in { } e.g. void Foo( int x){ return Boo(x); }) are referring to other functions in a valid manner.

    在这里,c++还检查定义的所有函数(例如,在{}中包含一个主体,例如void Foo(int x){return Boo(x);(})以有效的方式引用其他函数。

    The way it does that is by insisting that you provide at least a declaration of these other functions (e.g. void Boo(int); ) before you call it so it can check that you are calling it properly among other things. This can be done either directly in the cpp file where it is called or usually in an included header file.

    这样做的方式是坚持要求您至少提供这些其他函数的声明(例如void Boo(int));在你调用它之前,它可以检查你是否正确地调用了它。这可以直接在cpp文件中完成,也可以在包含的头文件中调用。

    Note that only the machine code that corresponds to functions defined in this cpp and included files gets built as the object (binary) version of this compilation unit (e.g. Foo) and not the ones that are merely declared (e.g. Boo).

    注意,只有与cpp中定义的函数和包含的文件对应的机器代码被构建为这个编译单元的对象(二进制)版本(例如Foo),而不是仅仅声明的那些(例如Boo)。

  3. Linking - This is the stage where C++ goes hunting for stuff declared and called in each compilation unit and links it to the places where it is getting called. Now if there was no definition found of this function the linker gives up and errors out. Similarly if it finds multiple definitions of the same function signature (essentially the name and parameter types it takes) it also errors out as it considers it ambiguous and doesn't want to pick one arbitrarily.

    链接——这是c++寻找在每个编译单元中声明和调用的内容并将其链接到被调用的位置的阶段。如果没有这个函数的定义链接器就会放弃错误。类似地,如果它发现同一函数签名的多个定义(本质上是它所使用的名称和参数类型),它也会出错,因为它认为它是不明确的,并且不想任意选择一个。

The latter is what is happening in your case. By doing a #include of the fun.cpp file, both fun.cpp and mainfile.cpp have a definition of funct() and the linker doesn't know which one to use in your program and is complaining about it.

后者是你的情况。通过做一些有趣的事情。cpp文件,都有趣。cpp和mainfile。cpp有一个funct()的定义,链接器不知道在您的程序中使用哪个函数,并且正在抱怨它。

The fix as Vaughn mentioned above is to not include the cpp file with the definition of funct() in mainfile.cpp and instead move the declaration of funct() in a separate header file and include that in mainline.cpp. This way the compiler will get the declaration of funct() to work with and the linker would get just one definition of funct() from fun.cpp and will use it with confidence.

上面Vaughn提到的修改是不将cpp文件包含在mainfile中,并定义了funct()。相反,cpp将函数()声明移到一个单独的头文件中,并将其包含在mainline.cpp中。这样,编译器将获得要处理的funct()的声明,链接器将从fun中获得funct()的一个定义。cpp将充满信心地使用它。

#2


21  

The problem is that if you include fun.cpp in two places in your program, you will end up defining it twice, which isn't valid.

问题是如果你考虑到乐趣。在程序的两个地方,cpp最终会定义两次,这是无效的。

You don't want to include cpp files. You want to include header files.

您不希望包含cpp文件。您希望包含头文件。

The header file should just have the class definition. The corresponding cpp file, which you will compile separately, will have the function definition.

头文件应该只有类定义。您将分别编译相应的cpp文件,它将具有函数定义。

fun.hpp:

fun.hpp:

#include <iostream>

class classA {
    friend void funct();
public:
    classA(int a=1,int b=2):propa(a),propb(b){std::cout<<"constructor\n";}
private:
    int propa;
    int propb;
    void outfun(){
        std::cout<<"propa="<<propa<<endl<<"propb="<<propb<< std::endl;
    }
};

fun.cpp:

fun.cpp:

#include "fun.hpp"

using namespace std;

void funct(){
    cout<<"enter funct"<<endl;
    classA tmp(1,2);
    tmp.outfun();
    cout<<"exit funct"<<endl;
}

mainfile.cpp:

mainfile.cpp:

#include <iostream>
#include "fun.hpp"
using namespace std;

int main(int nargin,char* varargin[]) {
    cout<<"call funct"<<endl;
    funct();
    cout<<"exit main"<<endl;
    return 0;
}

Note that it is generally recommended to avoid using namespace std in header files.

注意,一般建议避免在头文件中使用名称空间std。

#1


44  

Here is a highly simplified but hopefully relevant view of what happens when you build your code in C++.

这里有一个高度简化但希望与用c++构建代码相关的视图。

C++ splits the load of generating machine executable code in following different phases -

c++将生成机器可执行代码的负载分成以下几个阶段

  1. Preprocessing - This is where any macros - #defines etc you might be using get expanded.

    预处理-这是任何宏- #定义等等你可能正在使用的扩展。

  2. Compiling - Each cpp file along with all the #included files in that file directly or indirectly (together called a compilation unit) is converted into machine readable object code.

    编译—每个cpp文件以及该文件中包含的所有#文件(统称为编译单元)都被转换为机器可读的对象代码。

    This is where C++ also checks that all functions defined (i.e. containing a body in { } e.g. void Foo( int x){ return Boo(x); }) are referring to other functions in a valid manner.

    在这里,c++还检查定义的所有函数(例如,在{}中包含一个主体,例如void Foo(int x){return Boo(x);(})以有效的方式引用其他函数。

    The way it does that is by insisting that you provide at least a declaration of these other functions (e.g. void Boo(int); ) before you call it so it can check that you are calling it properly among other things. This can be done either directly in the cpp file where it is called or usually in an included header file.

    这样做的方式是坚持要求您至少提供这些其他函数的声明(例如void Boo(int));在你调用它之前,它可以检查你是否正确地调用了它。这可以直接在cpp文件中完成,也可以在包含的头文件中调用。

    Note that only the machine code that corresponds to functions defined in this cpp and included files gets built as the object (binary) version of this compilation unit (e.g. Foo) and not the ones that are merely declared (e.g. Boo).

    注意,只有与cpp中定义的函数和包含的文件对应的机器代码被构建为这个编译单元的对象(二进制)版本(例如Foo),而不是仅仅声明的那些(例如Boo)。

  3. Linking - This is the stage where C++ goes hunting for stuff declared and called in each compilation unit and links it to the places where it is getting called. Now if there was no definition found of this function the linker gives up and errors out. Similarly if it finds multiple definitions of the same function signature (essentially the name and parameter types it takes) it also errors out as it considers it ambiguous and doesn't want to pick one arbitrarily.

    链接——这是c++寻找在每个编译单元中声明和调用的内容并将其链接到被调用的位置的阶段。如果没有这个函数的定义链接器就会放弃错误。类似地,如果它发现同一函数签名的多个定义(本质上是它所使用的名称和参数类型),它也会出错,因为它认为它是不明确的,并且不想任意选择一个。

The latter is what is happening in your case. By doing a #include of the fun.cpp file, both fun.cpp and mainfile.cpp have a definition of funct() and the linker doesn't know which one to use in your program and is complaining about it.

后者是你的情况。通过做一些有趣的事情。cpp文件,都有趣。cpp和mainfile。cpp有一个funct()的定义,链接器不知道在您的程序中使用哪个函数,并且正在抱怨它。

The fix as Vaughn mentioned above is to not include the cpp file with the definition of funct() in mainfile.cpp and instead move the declaration of funct() in a separate header file and include that in mainline.cpp. This way the compiler will get the declaration of funct() to work with and the linker would get just one definition of funct() from fun.cpp and will use it with confidence.

上面Vaughn提到的修改是不将cpp文件包含在mainfile中,并定义了funct()。相反,cpp将函数()声明移到一个单独的头文件中,并将其包含在mainline.cpp中。这样,编译器将获得要处理的funct()的声明,链接器将从fun中获得funct()的一个定义。cpp将充满信心地使用它。

#2


21  

The problem is that if you include fun.cpp in two places in your program, you will end up defining it twice, which isn't valid.

问题是如果你考虑到乐趣。在程序的两个地方,cpp最终会定义两次,这是无效的。

You don't want to include cpp files. You want to include header files.

您不希望包含cpp文件。您希望包含头文件。

The header file should just have the class definition. The corresponding cpp file, which you will compile separately, will have the function definition.

头文件应该只有类定义。您将分别编译相应的cpp文件,它将具有函数定义。

fun.hpp:

fun.hpp:

#include <iostream>

class classA {
    friend void funct();
public:
    classA(int a=1,int b=2):propa(a),propb(b){std::cout<<"constructor\n";}
private:
    int propa;
    int propb;
    void outfun(){
        std::cout<<"propa="<<propa<<endl<<"propb="<<propb<< std::endl;
    }
};

fun.cpp:

fun.cpp:

#include "fun.hpp"

using namespace std;

void funct(){
    cout<<"enter funct"<<endl;
    classA tmp(1,2);
    tmp.outfun();
    cout<<"exit funct"<<endl;
}

mainfile.cpp:

mainfile.cpp:

#include <iostream>
#include "fun.hpp"
using namespace std;

int main(int nargin,char* varargin[]) {
    cout<<"call funct"<<endl;
    funct();
    cout<<"exit main"<<endl;
    return 0;
}

Note that it is generally recommended to avoid using namespace std in header files.

注意,一般建议避免在头文件中使用名称空间std。