关于C++包括另一个类

Regarding C++ Include another class

本文关键字:另一个 包括 C++ 关于      更新时间:2023-10-16

我有两个文件:

File1.cpp
File2.cpp

File1 是我的主类,它有 main 方法 File2.cpp 有一个类调用 ClassTwo,我想在我的 File1 中创建 ClassTwo 的对象.cpp

我将它们编译在一起

g++ -o myfile File1.cpp File2.cpp

但是当我尝试通过以下方式创建时

创建类二对象

ClassTwo ctwo;

它不起作用。

错误是

在此范围内未声明 ClassTwo。

这是我的主要.cpp

#include <iostream>
#include <string>
using namespace std;
int main()
{
//here compile error - undeclare ClassTwo in scope.
ClassTwo ctwo;
//some codes
}

这是我的文件2.cpp

#include <iostream>
#include <string>
using namespace std;
class ClassTwo
{
private:
string myType;
public:
void setType(string);
string getType();
};

void ClassTwo::setType(string sType)
{
myType = sType;
}
void ClassTwo::getType(float fVal)
{
return myType;
}

得到将我的 File2.cpp 拆分为另一个 .h 文件的响应,但如果我要声明一个类,我如何将其拆分为另一个 .h 文件,因为我需要维护变量(私有)和函数(公共)的公共和私有,以及如何在 main 方法中将 ClassTwo ctwo 添加到我的 File1.cpp

你的代码中的基本问题是什么?

你的代码需要分离到接口(.h)和实现(.cpp)。
编译器在编写类似

ClassTwo obj;

这是因为编译器需要为类型ClassTwo的对象保留足够的内存,因此它需要查看ClassTwo的定义。在C++中执行此操作的最常见方法是将代码拆分为头文件和源文件。类
定义位于头文件中,而类的实现位于源文件中。通过这种方式,可以轻松地将头文件包含在其他源文件中,这些文件需要查看他们创建的类对象的定义。

为什么我不能简单地将所有代码放在 cpp 文件中并将它们包含在其他文件中?

不能简单地将所有代码放在源文件中,然后将该源文件包含在其他文件中。C++标准规定,您可以根据需要多次声明实体,但只能定义一次(一个定义规则 (ODR))。包含源文件将违反 ODR,因为在包含该文件的每个翻译单元中都会创建实体的副本。

如何解决这个特殊问题?

您的代码应按如下方式组织:

//文件1.h

Define ClassOne 

//文件2.h

#include <iostream>
#include <string>

class ClassTwo
{
private:
string myType;
public:
void setType(string);
std::string getType();
}; 

文件1.cpp

#include"File1.h"
Implementation of ClassOne 

文件2.cpp

#include"File2.h"
void ClassTwo::setType(std::string sType)
{
myType = sType;
}
void ClassTwo::getType(float fVal)
{
return myType;
} 

主.cpp

#include <iostream>
#include <string>
#include "file1.h"
#include "file2.h"
using namespace std;
int main()
{
ClassOne cone;
ClassTwo ctwo;
//some codes
}

除了包含头文件之外,是否有任何其他方法?

如果您的代码只需要创建指针而不是实际对象,则不妨使用前向声明,但请注意,使用前向声明会增加对该类型的使用方式的一些限制,因为编译器将该类型视为不完整类型

C++(以及C)拆分了类型,函数和类的"声明"和"实现"。您应该在头文件(.h 或 .hpp)中"声明"所需的类,并将相应的实现放在 .cpp 文件中。 然后,当您希望在某处使用(访问)类时,#include 相应的头文件。

ClassOne.hpp:

class ClassOne
{
public:
ClassOne(); // note, no function body        
int method(); // no body here either
private:
int member;
};

第一类.cpp:

#include "ClassOne.hpp"
// implementation of constructor
ClassOne::ClassOne()
:member(0)
{}
// implementation of "method"
int ClassOne::method()
{
return member++;
}

主.cpp:

#include "ClassOne.hpp" // Bring the ClassOne declaration into "view" of the compiler
int main(int argc, char* argv[])
{
ClassOne c1;
c1.method();
return 0;
}

同时编译两个.cpp文件并不意味着他们"了解"彼此。 你必须创建一个文件,"告诉"你的File1.cpp,实际上有像ClassTwo这样的函数和类。 此文件称为头文件,通常不包含任何可执行代码。(也有例外,例如内联函数,但一开始忘记它们) 它们服务于声明性需求,只是为了告诉哪些功能可用。

当您拥有File2.cpp并将其包含在File1.cpp中时,您会看到一个小问题: 有两次相同的代码:一个在File1.cpp中,一个在其原点,File2.cpp

因此,您应该创建一个头文件,如File1.hppFile1.h(其他名称是可能的,但这只是标准名称)。它的工作原理如下:

文件1.cpp

void SomeFunc(char c) //Definition aka Implementation
{
//do some stuff
}

文件1.hpp

void SomeFunc(char c); //Declaration aka Prototype

对于干净的代码,您可以在File1.cpp顶部添加以下内容:

#include "File1.hpp"

下面,围绕File1.hpp的代码:

#ifndef FILE1.HPP_INCLUDED
#define FILE1.HPP_INCLUDED
//
//All your declarative code
//
#endif

这使您的头文件更干净,关于重复的代码。

如果你不想要标题,你需要转发声明类的名称:

class ClassTwo;

重要提示:这仅适用于某些情况,有关更多信息,请参阅 Als 的答案。

当您想将代码转换为 result(可执行文件、库或其他任何内容)时,有 2 个步骤:
1) 编译
2) 链接 在第一步中,编译器现在应该涉及一些事情,例如您使用的对象的大小,函数的原型以及可能的继承。 另一方面,链接
器希望在代码中找到函数和全局变量的实现。

现在,当您在File1.cpp中使用ClassTwo编译器对它一无所知,也不知道应该为它分配多少内存,或者例如它拥有的女巫成员,或者它是一个类和枚举,甚至是 int 的 typedef,因此编译器编译将失败。 添加File2.cpp解决寻找实现但编译器仍然不满意的链接器问题, 因为它对你的类型一无所知。

所以请记住,在编译阶段,您始终只使用一个文件(当然还有该文件包含的文件),而在链接阶段,您需要多个包含实现的文件。 由于 C/C++ 是静态类型的,并且它们允许它们的标识符用于多种目的(定义、typedef、枚举类等),因此您应该始终向编译器标识您的标识符,然后使用它,并且作为规则编译器应始终知道变量的大小!!