几年前参加了入门课程后,我试图重新学习 C++,但遇到了一些基本问题。我当前的问题是在尝试使用好友功能时出现的。这是我的代码,分为两个文件。
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;
}
我收到的错误是“‘funct()’的多重定义”。将其声明为友元函数时我是否使用了错误的语法?
这是一个高度简化但希望与您在 C++ 中构建代码时发生的情况相关的视图。
C++ 将生成机器可执行代码的负载分为以下不同阶段 -
预处理- 这是任何宏的位置 -#define
您可能正在使用 get Expanded 等。
-
编译- 每个 cpp 文件以及所有#include
该文件中的 .d 文件直接或间接(统称为编译单元)被转换为机器可读的目标代码。
在这里,C++ 还检查定义的所有函数(即包含函数体){
}
e.g.
void Foo( int x){ return Boo(x); })
以有效的方式引用其他函数。
它这样做的方式是坚持要求您至少提供这些其他函数的声明(例如void Boo(int);
)在你调用它之前,它可以检查你是否正确调用它。这可以直接在调用它的 cpp 文件中完成,或者通常在包含的头文件中完成。
请注意,只有与此 cpp 和包含文件中定义的函数相对应的机器代码才会构建为该编译单元的对象(二进制)版本(例如 Foo),而不是仅仅声明的机器代码(例如 Boo)。
Linking- 这是 C++ 寻找在每个编译单元中声明和调用的内容并将其链接到调用它的地方的阶段。现在,如果没有找到该函数的定义,链接器就会放弃并出错。类似地,如果它发现同一函数签名的多个定义(本质上是它所采用的名称和参数类型),它也会出错,因为它认为它不明确并且不想任意选择一个。
后者就是您的情况所发生的情况。通过做一个#include
of the fun.cpp
文件,两者fun.cpp
and mainfile.cpp
有一个定义funct()
并且链接器不知道在程序中使用哪一个并对此进行抱怨。
Vaughn 上面提到的修复方法是不包含具有以下定义的 cpp 文件funct()
in mainfile.cpp
而是移动声明funct()
在一个单独的头文件中并将其包含在mainline.cpp
。这样编译器就会得到声明funct()
来使用并且链接器只会得到一个定义funct()
from fun.cpp
并会放心地使用它。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)