将C 源文件分为多个文件的麻烦

Troubles separating C++ source file into multiple files

本文关键字:文件 麻烦 源文件      更新时间:2023-10-16

让我确切地指定我要做的事情,我需要将我的foo-bar程序拆分为五个单独的文件:main,foo.h,foo.cpp,bar.h.h,bar.cpp。我的标题文件(foo.h and 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 func1n";
    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的成员

我的问题是:我在做什么错,还有更好的方法可以解决我要做的事情吗?

预先感谢您。

此代码中表现出多个误解。完全纠正它们比单独描述和讨论它们要容易得多。

让我们从依赖树的底部开始。底部是一个虚拟类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文件的多个包含,因为我们永远不会包含它。

现在FooBar类的父母,为我们做一些真正的工作。再次,在类声明中声明了所有方法。

#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 func1n";
    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;}

现在让我们继续构建我们的项目。如果您使用的是易于描述为CLI命令序列的GCC。由于您正在使用Visual Studio,因此必须通过GUI执行相应的操作。

  1. 第一次编译foo

    g++ -c -Wall foo.cpp

  2. 下一个编译条

    g++ -c -Wall bar.cpp

  3. 编译Main

    g++ -c -Wall main.cpp

  4. 现在将它们全部链接在一起

    g++ -o main foo.o bar.o main.o

  5. 终于运行它,voila

    内部func1        数据是25    在func2内34        数据是25

您切勿#include .cpp文件。而是将每个.cpp文件编译到对象文件中,然后将它们链接到可执行文件中。

在预处理器阶段,编译器将所有#include D文件拿走,并将它们视为将它们置于一个大型程序中。有时,某些文件可能是多次#include D。在标题文件中,声明可以重复,但是来自源文件的多个定义会导致错误。(您可能没有这个问题,因为您在源文件中使用了警卫。)

创建对象文件时,编译器将使用标头文件来检查名称和类型,但是不需要实际的定义。发现的定义 汇总到对象文件中。单独的对象文件的目的是将这些定义的汇编分为模块化单元。