C ++ где разместить включает - PullRequest
0 голосов
/ 19 ноября 2010

У меня есть класс Vehicle (vehicle.h и vehicle.cpp). Visual Studio выдаёт мне ошибки, если я не добавлю включения в заголовочный файл. Почему это? В моих предыдущих 2 заданиях я поместил include в файл .cpp, и у меня не было проблем. Вот что я хочу работать, но это не так:

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

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

truck.h:

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

};

truck.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'

Ответы [ 3 ]

3 голосов
/ 19 ноября 2010

Вы объявляете экземпляр Person в заголовочном файле вашего транспортного средства, поэтому компилятору требуется полное объявление. Если вы используете указатель или ссылку на человека, вы можете просто объявить его с помощью class Person;.

РЕДАКТИРОВАТЬ: Кроме того, возьмите это using namespace std; и префикс ваших переменных с std::. Это спасет от болей в будущем.

EDIT2: Вам также нужно включить <string> в заголовочный файл.

Хорошо, здесь я собираюсь постараться сделать это просто и красиво.

Когда ваш компилятор обрабатывает ваши файлы реализации (.cpp), он включает указанные вами заголовки (в данном случае это будут vehicle.h и person.h). Для каждого файла реализации компилятору необходимо знать о каждом используемом вами типе, чтобы он мог генерировать правильный код.

Когда он обрабатывает включаемый файл, ему все равно нужно знать все . Таким образом, в вашем заголовочном файле vehicle.h вы используете Person. В тот момент, когда компилятор достигнет этого, он должен знать, как создать человека. Ваш vehicle.cpp включает person.h до vehicle.h, так что никаких проблем. ЗА vehicle.cpp. Все, что включает vehicle.h, но не включает person.h, вызовет ошибки компиляции.

Так, когда вы можете избежать предварительного объявления и указать указатель или ссылку?

Объявление указателя или ссылки не требует от компилятора каких-либо сведений об этом классе или структуре в заголовочном файле. Вы просто говорите компилятору, что у вас есть намерение сделать это. При условии, что класс заранее объявлен так:

class Person;

Тогда компилятор говорит: «Окей, я возьму это». Затем вы включаете соответствующий файл в свою реализацию, компилятор понимает, что вы имеете в виду, и все с радостью возвращаются домой из бара.

В вашем случае, я думаю, произошло то, что файл реализации для транспортного средства выглядит хорошо на бумаге, но что-то еще включает vehicle.h и нет никакой подсказки о том, что такое Person.

Ваше решение

Либо включите person.h в vehicle.h, если необходимо, в противном случае измените конструктор так, чтобы он ссылался на персона (и участника), и перешлите объявление Person. Однако, не зная, что делает ваша программа, я не могу сказать, что даже передача по ссылке верна.

И, пожалуйста, удалите using namespace std; и измените string на std::string:)

1 голос
/ 19 ноября 2010

Содержит ли person.h строку #include "vehicle.h"?Круговыми зависимостями сложнее управлять в C ++, чем, например, в Java или C #.Вы можете легко попасть в ситуацию, когда вам нужно #include "Person.h" до #include "Vehicle.h", но вам также нужно #include "Vehicle.h" до #include "Person.h".

Во многих случаях вы должны сказать компилятору: «Персона - это имякласса, но я еще не готов дать вам определение ".Для этого вы можете сказать: class Person; Это решает проблему циклической ссылки.

Кроме того, создание большого количества копий объекта Person, вероятно, не имеет смысла, но это то, что вы делаете с паролем.по значению.Похоже, вы пришли из среды Java или C #, где переменные типа класса автоматически (и всегда) были ссылками.В C ++ вы должны запросить ссылку через Person* (указатель может быть изменен для указания на другой экземпляр, например, ссылки Java и C #) или Person& (ссылка C ++, навсегда прикрепленная к конкретному экземпляру).).

1 голос
/ 19 ноября 2010

Когда вы помещаете объект другого класса в ваш класс, компилятору необходимо знать полное определение этого класса.Самый простой способ запомнить это правило - понять, что вы не можете знать sizeof (Vehicle), пока не узнаете sizeof (Person), и компилятор тоже не может.Указатели и ссылки на другой класс в порядке, если вы сначала сделаете предварительное объявление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...