将C ++源文件分成多个文件的麻烦

时间:2017-12-09 02:11:40

标签: c++

让我准确说明我要做的事情,我需要将我的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类的成员

我的问题是:我做错了什么,是否有更好的方法去做我想做的事情?

提前谢谢。

2 个答案:

答案 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执行相应的操作。

  1. 首先编译Foo

    g++ -c -Wall foo.cpp

  2. 接下来编译Bar

    g++ -c -Wall bar.cpp

  3. 编译主要

    g++ -c -Wall main.cpp

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

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

  5. 最后运行它并瞧

  6.     Inside func1
            Data is 25
        Inside func2 with 34
            Data is 25