Использование предварительных объявлений для встроенных типов данных - PullRequest
2 голосов
/ 07 июня 2010

Я понимаю, что везде, где возможно, мы будем использовать предварительные объявления вместо включений для ускорения компиляции.

У меня есть класс Person, подобный этому.

#pragma once

#include <string>

class Person
{
public:
    Person(std::string name, int age);
    std::string GetName(void) const;
    int GetAge(void) const;
private:
    std::string _name;
    int _age;
};

и классStudent вот так

#pragma once

#include <string>

class Person;

class Student
{
public:
    Student(std::string name, int age, int level = 0);
    Student(const Person& person);
    std::string GetName(void) const;
    int GetAge(void) const;
    int GetLevel(void) const;
private:
    std::string _name;
    int _age;
    int _level;
};

В Student.h у меня есть предварительное объявление class Person; для использования Person в конструкторе преобразования.Хорошо.Но я сделал #include <string>, чтобы избежать ошибки компиляции при использовании std::string в коде.Как использовать предварительное объявление здесь, чтобы избежать ошибки компиляции?Возможно ли это?

Спасибо.

Ответы [ 5 ]

4 голосов
/ 07 июня 2010

С момента использования string как

std::string _name;
//^^^^^^^^^ concrete member    

понадобится вся структура string, поэтому необходимо объявление. Вы должны #include <string>.


Объявление string можно опустить, если вы напишите, например,

std::string* _name;
//^^^^^^^^^^ pointer or reference

, который вы могли бы использовать для предварительного объявления, но я все же рекомендую вам , а не , чтобы сделать это, потому что std::string не простой тип структуры, такой как Person или Student, а очень сложный тип, включающий множество шаблонов :

template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
class basic_string { ... };
typedef basic_string<char> string;

Если вы передадите декларацию неправильно (например, class string;), компиляция завершится неудачно, когда вы действительно ее используете из-за конфликтующего типа.

2 голосов
/ 07 июня 2010

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

Таким образом, если вы определите Student как это

class Student
{
public:
    ...
    Student(const Person person);
    ...
private:
    Person person;
};

любой из вышеперечисленных учеников заставит вас #include Person.h в вашем заголовке.

Вы хорошо понимаете, что предварительное объявление помогает избежать зависимостей компиляции, тем самым сокращая время компиляции. Однако это касается главным образом пользовательских заголовков, потому что они часто меняются. Заголовки стандартных библиотек не будут меняться, поэтому в этих случаях экономия не будет существенной.

1 голос
/ 07 июня 2010

Вы можете использовать только предварительные объявления для идентификации типа, например, когда вы используете объявленный тип в прототипе параметра указателя на функцию / метод. Если вы собираетесь объявить переменную-член (т.е. std :: string _name;), то компилятору нужно немного больше, чем может дать предварительное объявление. Например, если кто-то делает sizeof (Student), компилятор должен иметь доступ ко всей декларации, чтобы определить размер.

0 голосов
/ 07 июня 2010

Форвардные объявления используются для уменьшения количества включаемых и разрешения циклических зависимостей. Но при использовании пересылок в общедоступном или защищенном интерфейсе вашего класса вы возлагаете бремя включения правильных заголовочных файлов на пользователей вашего класса. Кроме того, типы пересылки, определенные в STL, могут работать не так, как ожидалось. Например, std :: string может быть определен как typedef basic_string<char> string;. Объявление его вперед с помощью namespace std{ class string;} приведет к ошибке компиляции.

0 голосов
/ 07 июня 2010

Может также рассмотреть возможность использования наследования.

#include "Person.h" // i am afraid you need to

class Student : public Person
{
     ...

     protected:
         int _level;
         // no name and age, that is inhertianced from person
         // (if you want to access them from student, you maybe need to make them protected)
 };
...