Рекомендуемый C Включает Практику

#c #include

Вопрос:

В следующем сценарии, каков был бы наилучший подход для включения <string> заголовка?

main.cpp

 #include "extra.h"

int main() {
    func("A string");
    return 0;
}
 

дополнительно.ч

 #ifndef EXTRA_H
#define EXTRA_H

    #include <string>

    void func(std::string);

#endif
 

extra.cpp

 #include <iostream>
#include "extra.h"

void func(std::string str) {
    std::cout << str << 'n';
}

 

Комментарии:

1. Код, который у вас есть, выглядит правильно. Не могли бы вы более конкретно сформулировать свой вопрос?

2. Извините за отсутствие деталей. Я прошел через несколько различных руководств, и некоторые из них рекомендуют включать заголовочные файлы в файлы .cpp, а не полагаться на транзитивное включение, поэтому мне было интересно, следует ли добавить #include <string> строку в extra.cpp и main.cpp так же хорошо.

3. Что такое «лучшее», довольно субъективно. Лично я, как правило, включаю то, что использую, но в данном случае это может быть больше похоже на стиль. Если одни и те же разработчики контролируют .h файлы .cpp и , и вы точно знаете, что extra.h включает <string> , то вы можете счесть необязательным включать его в .cpp . Но это только мое мнение.

Ответ №1:

Ваш extra.h включает <string> в себя, потому что он использует его напрямую. В вашем нет прямого использования std::string main.cpp , поэтому было бы странно включать <string> его туда.

Далее, в том числе <string> в extra.cpp совершенно излишним, поскольку использовать std::string это в функции, которые вы знаете, объявлен в extra.h плюс на содержание двух extra файлов может быть выполнена в ходе одной операции, так что нет необходимости беспокоиться о extra.h вдруг не включая <string> , а потом ломать extra.cpp , потому что они будут сохраняться вместе.

Ответ №2:

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

Например, main.h

 #pragma once

// if your header uses a full type (see function h)
// it needs to know the size of the type
// then include header file for that type in your header

#include <string>
void h(std::string str);

// if your header only has references or pointers to a type
// then add a forward declaration of that type.
// The compiler only has to know the size for the reference/pointer

struct struct_t; 

void f(const struct_tamp; s);
void g(const struct_t* s);
 

А потом main.cpp

 #include "main.h"
#include <iostream>
// #include <string> not really needed already done in "main.h"

// full declaration of struct_t in the place where it is needed.
// note this could also be in done in its own header file. 
struct struct_t
{
    int value1;
    int value2;
};

void f(const struct_tamp; s)
{
    std::cout << s.value1 << std::endl;
    std::cout << s.value2 << std::endl;
}

void g(const struct_t* s)
{
    std::cout << s->value1 << std::endl;
    std::cout << s->value2 << std::endl;
}

void h(std::string s)
{
    std::cout << s << std::endl;
}

int main()
{
    struct_t values{ 0, 42 };
    f(values);
    g(amp;values);
    h("Hello World!");
}
 

Комментарии:

1. Будет ли обертывание строки в структуру (структуру, класс и т. Д.) Более эффективным, Чем включение <string> заголовка в extra.h?

2. Я приношу извинения за путаницу, обертывание строки было не тем, что я хотел показать, я обновил пример.

3. Если вы создаете набор заголовочных файлов для клиента, то да, скрытие сложных типов от клиента является допустимым подходом, но тогда я обычно использую абстрактные базовые классы (интерфейсы) и шаблон pimpl : en.cppreference.com/w/cpp/language/pimpl . Но это был не ваш первоначальный вопрос 🙂