让我准确说明我要做的事情,我需要将我的foo-bar程序拆分为五个单独的文件:main,foo.h,foo.cpp,bar.h,bar.cpp。我的头文件(foo.h和bar.h)用于包含相应类的声明,而c ++文件(foo.cpp和bar.cpp)用于定义类。
我使用Visual Studio,到目前为止,我显示红旗的唯一文件是我的主文件。这是我的代码到目前为止,我将包括我的主文件中抛出的错误:
的main.cpp
#include <iostream>
#include "foo.h"
#include "foo.cpp"
#include "bar.h"
#include "bar.cpp"
using namespace std;
int main() {
Bar b(25); /*I am getting a red flag under the 25, stating there is no constructor that can convert int to Bar*/
b.func1(); /*I'm getting a red flag under func1 and func2 stating neither of them are members of Bar*/
b.func2(34);
return 0;}
foo.h中
#ifndef foo_h
#define foo_h
#include "foo.cpp"
class Foo {};
#endif
Foo.cpp中
#ifndef foo_c
#define foo_c
#include "foo.h"
#include "bar.cpp"
private:
int data;
public:
Foo(int d) : data(d) {}
int get_data() { return data; }
virtual void func1() = 0;
virtual int func2(int d) = 0;
#endif
bar.h
#ifndef bar_h
#define bar_h
#include "bar.cpp"
#include "foo.h"
class Bar : public Foo {};
#endif
bar.cpp
#ifndef bar_c
#define bar_c
#include "bar.h"
#include "foo.h"
#include "foo.cpp"
Bar(int d) : Foo(d) {}
void func1() {
cout << "Inside func1\n";
cout << "\tData is " << get_data() << endl;
}
int func2(int d) {
cout << "Inside func2 with " << d << endl;
cout << "\tData is " << get_data() << endl;
return d;
}
#endif
我的程序一直工作,直到我将它拆分,但现在它在我尝试编译时不断向我发送此消息,并且我的主代码中有几个红色标记。这是控制台告诉我的:
没有合适的构造函数将int转换为Bar
func1不是类Bar的成员
func2不是Bar类的成员
我的问题是:我做错了什么,是否有更好的方法去做我想做的事情?
提前谢谢。
答案 0 :(得分:1)
您绝不应该#include
.cpp
个文件。而是将每个.cpp
文件编译成目标文件,并将它们链接到可执行文件中。
在预处理器阶段,编译器会获取所有#include
个d文件,并将它们视为连接成一个大型程序。有时,某些文件可能会多次#include
次。头文件中的声明可能会重复,但源文件中的多个定义会导致错误。 (您可能不会遇到此问题,因为您在源文件中使用了包含警戒。)
创建目标文件时,编译器使用头文件来检查名称和类型,但不需要实际定义。找到 的定义将编译到目标文件中。单独目标文件的目的是将这些定义的编译分离为模块化单元。
答案 1 :(得分:1)
此代码中出现了多个误解。或许完全纠正它们比单独描述和讨论它们更容易。
让我们从依赖树的底部开始。底部是虚拟课程Foo
。这是正确的声明。
#ifndef foo_h
#define foo_h
class Foo {
private:
int data;
public:
Foo(int);
int get_data();
virtual void func1() = 0;
virtual int func2(int) = 0;
};
#endif
请注意,我们在头文件中包含其所有方法的声明。但是,非虚拟方法的实现将移出foo.cpp
文件。
#include "foo.h"
Foo::Foo(int d) : data(d) { }
int Foo::get_data() { return data; }
请注意,我们不需要任何特殊设备来防止多次包含.cpp
文件,因为我们不会包含它。
现在Foo
是类Bar
的父级,它为我们做了一些真正的工作。再一次,它的所有方法都在类声明中声明。
#ifndef bar_h
#define bar_h
#include "foo.h"
class Bar : public Foo {
public:
Bar(int);
void func1();
int func2(int);
};
#endif
它的实现位于相应的编译单元bar.cpp
中。在实现类方法时,我们通过将类名添加到方法名称来指示方法所属的类,例如, Bar::func1
。
#include "bar.h"
#include "foo.h"
#include <iostream>
Bar::Bar(int d) : Foo(d) {};
using namespace std;
void Bar::func1() {
cout << "Inside func1\n";
cout << "\tData is " << get_data() << endl;
}
int Bar::func2(int d) {
cout << "Inside func2 with " << d << endl;
cout << "\tData is " << get_data() << endl;
return d;
}
最后,我们在main.cpp
中使用它,只需要进行少量更改。
#include <iostream>
#include "foo.h"
#include "bar.h"
using namespace std;
int main() {
Bar b(25);
b.func1();
b.func2(34);
return 0;}
现在让我们继续构建我们的项目。如果您使用GCC,那么很容易将其描述为一系列CLI命令。由于您使用的是Visual Studio,因此必须通过GUI执行相应的操作。
首先编译Foo
g++ -c -Wall foo.cpp
接下来编译Bar
g++ -c -Wall bar.cpp
编译主要
g++ -c -Wall main.cpp
现在将它们链接在一起
g++ -o main foo.o bar.o main.o
最后运行它并瞧
Inside func1 Data is 25 Inside func2 with 34 Data is 25