【问题标题】:C++ where to place includesC++ 的放置位置包括
【发布时间】:2011-05-12 07:28:16
【问题描述】:

我有一个类 Vehicle(vehicle.h 和 vehicle.cpp)。如果我不将包含内容放在头文件中,Visual Studio 会给我错误。为什么是这样?在我之前的 2 个作业中,我将包含在 .cpp 文件中并且没有任何问题。这是我想要工作但不是:

车辆.h:

#ifndef VEHICLE_H
#define VEHICLE_H

using namespace std;
class Vehicle
{
public:
    Vehicle();
    Vehicle(string mfr, int cylinders, Person owner);
    string getManufacturer();
    int getNumOfCylinders();
    Person getOwner();
private:
    string manufacturer;
    int numOfCylinders;
    Person owner;
};
#endif

车辆.cpp:

#include <iostream>
#include <string>
using namespace std;
#include "person.h"
#include "vehicle.h"

Vehicle::Vehicle()
{
    //Initialize with defaults
}
Vehicle::Vehicle(string mfr, int cylinders, Person owner)
{
    //Initialize with parameters
}
string Vehicle::getManufacturer()
{
    return manufacturer;
}
int Vehicle::getNumOfCylinders()
{
    return numOfCylinders;
}
Person Vehicle::getOwner()
{
    return owner;
}

person.h:

    #ifndef PERSON_H
#define PERSON_H
class Person {
    public:
        //default constructor
        Person();
        //constructor with two parameters
        Person(string the_name, string no);
        //accessor member functions
        string get_name() const;
        string getDriverLicenseNo() const;
        //overloaded equal operator 
        bool operator==(const Person& p);

        //overloaded extraction operator
        friend istream& operator >> (istream& in, Person& p);
        //overloaded insertion operator
        friend ostream& operator <<(ostream& out, Person& p);
    private:
        string name;
        string drivingLicenseNo;
};
#endif

person.cpp:

    #include <iostream>
#include <string>
using namespace std;
#include "person.h"


//default constructor
Person::Person(){}
//constructor with two parameters
Person::Person(string the_name, string no){}
//accessor member functions
string Person::get_name() const
{
    return name;
}
string Person::getDriverLicenseNo() const
{
    return drivingLicenseNo;
}
//overloaded equal operator 
bool Person::operator==(const Person& p)
{
    return false;
}

//overloaded extraction operator
istream& operator >> (istream& in, Person& p)
{
    return in;
}
//overloaded insertion operator
ostream& operator <<(ostream& out, Person& p)
{
    return out;
}

卡车.h:

#include "vehicle.h"
class Truck: public Vehicle
{

};

卡车.cpp:

#include "person.h"
#include "vehicle.h"
//implement truck here

例如几个错误:

错误 C2061:语法错误:标识符“字符串”

错误 C2146:语法错误:缺少 ';'在标识符“getManufacturer”之前

错误 C2061:语法错误:标识符“字符串” 错误 C2535:“Person::Person(void)”:成员函数已定义或声明
错误 C2146:语法错误:缺少“;”在标识符“get_name”之前

错误 C4430:缺少类型说明符 - 假定为 int。注意:C++ 不支持 default-int

错误 C4430:缺少类型说明符 - 假定为 int。注意:C++ 不支持 default-int

错误 C2146:语法错误:缺少 ';'在标识符“getDriverLicenseNo”之前

【问题讨论】:

  • 你能把错误信息作为cmets放在代码中,这样我们就知道每个人在说哪一行了吗?
  • 当然,我猜这不是问题,但此时我没有移动任何东西,我总共有 41 个错误。有没有办法让视觉工作室以某种方式将其放入代码中?当我移动包含时,错误消失了,所以我很确定就是这样。我只是想了解如何正确地做到这一点,而不是每次都与编译器争吵。
  • 请永远不要将using namespace std; 放在标题中。

标签: c++ include


【解决方案1】:

您正在车辆头文件中声明Person 的实例,因此编译器需要完整声明。如果您使用的是一个人的指针或引用,您可以简单地使用 class Person; 转发声明它。

编辑:另外,取出 using namespace std; 并在变量前加上 std::。以后会省很多球痛。

EDIT2:您还需要在头文件中包含&lt;string&gt;

好的,就这样吧,我会尽量保持它的美观和简单。

当您的编译器处理您的实现文件 (.cpp) 时,它会包含您指定的标头(在本例中为 vehicle.hperson.h)。对于每个实现文件,编译器都需要了解您使用的每种类型,以便生成正确的代码。

当它处理一个包含文件时,它仍然需要知道一切。所以在你的vehicle.h 头文件中,你使用的是Person。在编译器达到这一点时,它需要知道如何构造 person。您的vehicle.cppvehicle.h 之前包含person.h,所以没问题。 vehicle.cpp。包含vehicle.h 但不包含person.h 的任何其他内容都会导致编译器错误。

那么你什么时候可以摆脱前向声明并使用指针或引用?

声明指针或引用不需要在头文件中告诉编译器有关该类或结构的任何信息。您只是告诉编译器您打算这样做。前提是类是这样向前声明的:

class Person;

然后编译器会说“okee dokee,我会接受的。”然后你在你的实现中包含相关文件,编译器会看到你的意思,每个人都开心地从酒吧回家。

我认为,在您的情况下,车辆的实现文件在纸面上看起来不错,但其他内容包括 vehicle.h 并且不知道 Person 是什么。

您的解决方案

如果必须,要么在 vehicle.h 中包含 person.h,否则更改构造函数以引用人员(和成员),并转发声明 Person。但是,由于不知道您的程序在做什么,我不能说即使是通过引用传递也是正确的。

请删除 using namespace std; 并将您的 string 更改为 std::string :)

【讨论】:

  • 他应该将它包含在标题中。但由于他在“vehicle.h”之前包含“person.h”,它也应该可以工作。这不好,但它应该工作。所以知道确切的错误信息会很好。
  • 您能再解释一下吗?我在vehicle.cpp中的person.h文件中添加了一个include,这还不够吗?
  • @rstevens,我确实抓住了这一点,但我想知道是否还有其他东西在起作用,包括vehicle.h。对于编译器来说,我只能假设它被包含在其他地方。
  • @Pete,您是否在其他地方包含了vehicle.h?如果是这样,它将不会获得您在实现.cpp 文件中放置的包含。如果您在头文件中实例化它,编译器必须知道Person。您的vehicle.cpp 文件可能编译得很好,但其他文件不会。正如 rstevens 所说,特定的错误消息在这里可能会有所帮助。
  • @Moo,我在其他地方使用了 includevehicle.h,但由于#ifndef 的东西,我觉得它没问题?
【解决方案2】:

当您将另一个类的对象放入您的类时,编译器需要知道该类的完整定义。记住这条规则的最简单的方法是认识到只有知道 sizeof(Person) 才能知道 sizeof(Vehicle),编译器也不能。如果您先进行前向声明,则可以使用指向另一个类的指针和引用。

【讨论】:

    【解决方案3】:

    person.h 是否包含#include "vehicle.h" 行?循环依赖在 C++ 中比例如在 C++ 中更难管理。 Java 或 C#。您很容易遇到这样一种情况:在 #include "Vehicle.h" 之前需要 #include "Person.h",但在 #include "Person.h" 之前还需要 #include "Vehicle.h"

    在许多情况下,您必须告诉编译器“Person 是一个类的名称,但我还没有准备好给你定义”。为此,您可以说 class Person; 这解决了循环引用问题。

    另外,制作大量 Person 对象的副本可能没有意义,但这就是您使用传递值所做的事情。看起来您确实来自 Java 或 C# 环境,其中类类型的变量自动(并且始终)是引用。在 C++ 中,您必须通过 Person*(指针,可以更改为指向不同的实例,如 Java 和 C# 引用)或 Person&amp;(C++ 引用,永久附加到特定实例)请求引用)。

    【讨论】:

    • 我的人没有任何包含到 Vehicle.h 中。
    猜你喜欢
    • 2022-11-10
    • 2017-11-20
    • 1970-01-01
    • 2018-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多