Форвардные объявления, которые включают std :: vector и т. Д. - PullRequest
2 голосов
/ 26 октября 2011

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

// Prototype of my function - i don't want to include <vector> to declare it!
int DoStuff(const std::vector<int>& thingies);

Я слышал, что запрещено / невозможно объявить форвард std::vector.Теперь этот ответ на несвязанный вопрос предлагает переписать мой код следующим образом:

stuff.h

class VectorOfNumbers; // this class acts like std::vector<int>
int DoStuff(const VectorOfNumbers& thingies);

stuff.cpp

// Implementation, in some other file
#include <vector>
class VectorOfNumbers: public std::vector<int>
{
    // Define the constructors - annoying in C++03, easy in C++11
};

int DoStuff(const VectorOfNumbers& thingies)
{
    ...
}

Теперь, если я буду использовать VectorOfNumbers вместо std::vector<int> во всех контекстах моего проекта, все будет хорошо, и мне не нужно #include <vector>в моих заголовочных файлах больше!

Есть ли у этой техники серьезные недостатки?Может ли выигрыш от возможности заранее объявить vector их перевесить?

Ответы [ 5 ]

6 голосов
/ 26 октября 2011

Если вы когда-либо удаляете VectorOfNumbers как std::vector<int> (и поскольку вы использовали публичное наследование, это преобразование неявно), вы вступаете в область неопределенного поведения. Вероятно, это скорее случится случайно, чем можно подозревать.

Я никогда лично не замечал значительного замедления компиляции по сравнению с включением vector там, где это необходимо, но если вы действительно хотите изолировать включение, используйте интерфейс API клиента, который не знает о базовом типе контейнера (vector ) и включите vector в один исходный файл.

3 голосов
/ 26 октября 2011

Причина, по которой я бы не стал этого делать:

const std::vector<int>& a = a_3rd_party_lib::get_data(); // this type is out of your control
DoStuff(a); // you cannot pass it to this function! 
0 голосов
/ 02 сентября 2017

Вместо наследования вы можете использовать состав:

// Implementation, in some other file
#include <vector>
class VectorOfNumbers
{
    public:

    std::vector<int>& container;

    VectorOfNumbers(std::vector<int>& in_container)
        : container(in_container)
    {
    }
};

int DoStuff(const VectorOfNumbers& thingies)
{
    std::sort(thingies.container.begin(), thingies.container.end());
    // ...
}

Недостатком является дополнительное имя переменной при каждом доступе.

Кроме того, вам нужно, чтобы эта реализация находилась взаголовочный файл, включенный в cpps, чтобы они знали, что они могут делать с VectorOfNumbers.

По сути, просто создаем оболочку для вашего вектора.Это похоже на облегченную версию PImpl (мы заботимся только об избежании зависимостей заголовка, поэтому нам не нужна полная развязка указателя).Это позволяет избежать проблем, поднятых Марком Б и Ибунгалобиллом.

Но я не думаю, что это действительно того стоит.

0 голосов
/ 26 октября 2011

Это хорошо работает для интерфейса класса, но не для реализации. Если в вашем классе есть vector члены, вы должны #include <vector>, иначе определение класса не скомпилируется.

0 голосов
/ 26 октября 2011

Вы включаете <vector> в заголовочный файл.Заголовок <vector> будет создан для предотвращения нескольких включений, так что вы просто должны включать его везде, где вам нужно.

...