开发者

C++ where to place includes

I have a class Vehicle (vehicle.h and vehicle.cpp). Visual Studio is giving me errors if I don't put the includes inside of the header file. Why is this? In my previous 2 assignments I put the includes in the .cpp file and had no issues. Here is what I want to work but isn't:

vehicle.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

vehicle.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;
}

pers开发者_JS百科on.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;
}

truck.h:

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

};

truck.cpp:

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

Couple of errors for example:

error C2061: syntax error : identifier 'string'

error C2146: syntax error : missing ';' before identifier 'getManufacturer'

error C2061: syntax error : identifier 'string' error C2535: 'Person::Person(void)' : member function already defined or declared

error C2146: syntax error : missing ';' before identifier 'get_name'

error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

error C2146: syntax error : missing ';' before identifier 'getDriverLicenseNo'


You are declaring an instance of Person in your vehicle header file, therefore the compiler needs the full declaration. If you were using a pointer or reference to a person, you could simply forward declare it with class Person;.

EDIT: Also, take out that using namespace std; and prefix your variables with std::. It'll save a lot of ball-ache in the future.

EDIT2: You also need to include <string> in your header file.

Ok, here goes, I'm going to try and keep it nice and simple.

When your compiler processes your implementation files (.cpp) it includes the headers you have specified (in this case, that would be vehicle.h and person.h). For every implementation file, the compiler needs to know about every single type that you use so that it can generate the correct code.

When it processes an include file, it still needs to know everything. So in your vehicle.h header file, you are using Person. At the point that the compiler hits that, it needs to know how to construct person. Your vehicle.cpp includes person.h before vehicle.h so, no problem. FOR vehicle.cpp. Anything else that includes vehicle.h but does not include person.h, will give you compiler errors.

So when can you get away with a forward declaration and user a pointer or reference?

Declaring a pointer, or a reference does not require telling the compiler anything about that class or structure in the header file. You're merely telling the compiler that you have an intention to do so. Provided that the class is forward declared thusly:

class Person;

Then the compiler says "okee dokee, I'll take that." Then you include the relevant file in your implementation, the compiler sees what you mean and everybody walks home from the bar happy.

What has happened in your case, I think, is that the implementation file for vehicle looks good on paper, but something else includes vehicle.h and there is no clue about what a Person is.

Your solution

Either include person.h in vehicle.h if you must, otherwise change that constructor to take a reference to person (and the member), and forward declare Person. However, not knowing what your program is doing I can't say that even passing-by-reference is correct.

And please, remove using namespace std; and change your string's to std::string :)


When you put an object of another class into your class, the compiler needs to know the entire definition of that class. The easiest way to remember this rule is to realize that you can't know sizeof(Vehicle) until you know sizeof(Person), and neither can the compiler. Pointers and references to another class are OK if you do a forward declaration first.


Does person.h contain the line #include "vehicle.h"? Circular dependencies are harder to manage in C++ than e.g. Java or C#. You can easily get into a situation where you need #include "Person.h" before #include "Vehicle.h", but you also need #include "Vehicle.h" before #include "Person.h".

In many cases you have to tell the compiler "Person is the name of a class, but I'm not ready to give you the definition yet". For that you can say class Person; This unravels the circular reference problem.

Also, making lots of copies of a Person object probably doesn't make sense, but that's what you're doing with pass-by-value. It really looks like you're coming from a Java or C# environment, where variables of class type automatically (and always) were references. In C++, you have to ask for a reference via either Person* (a pointer, can be changed to point to a different instance, like Java and C# references) or Person& (a C++ reference, permanently attached to a particular instance).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜