Должен ли C ++ исключать заголовочные файлы? - PullRequest
68 голосов
/ 15 апреля 2009

Многие языки, такие как Java, C #, не отделяют объявление от реализации. В C # есть концепция частичного класса, но реализация и объявление по-прежнему остаются в одном файле.

Почему C ++ не имеет ту же модель? Разумнее ли иметь заголовочные файлы?

Я имею в виду текущие и будущие версии стандарта C ++.

Ответы [ 17 ]

2 голосов
/ 11 сентября 2009

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

2 голосов
/ 13 июля 2009

Существует значение в определении интерфейса класса в отдельном компоненте к файлу реализации.

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

У Modula 2 были правильные идеи, модули определения и реализации. http://www.modula2.org/reference/modules.php

Ответ Java / C # является неявной реализацией того же (хотя и объектно-ориентированного.)

Заголовочные файлы - это ключ, потому что заголовочные файлы выражают детали реализации (например, частные переменные.)

Переходя к Java и C #, я обнаружил, что если для языка требуется поддержка IDE для разработки (такая, что интерфейсы общедоступных классов доступны в браузерах классов), то это может быть утверждение о том, что код не стоит на своем собственные достоинства как особо читаемые.

Я нахожу смесь интерфейса с деталями реализации довольно ужасной.

Важно отметить, что отсутствие возможности документировать сигнатуру публичного класса в сжатом хорошо прокомментированном файле, не зависящем от реализации, указывает на то, что дизайн языка написан для удобства авторства, а скорее для удобства обслуживания. Ну, я сейчас болтаю о Java и C #.

1 голос
/ 15 апреля 2009

Если вы хотите узнать причину, по которой это никогда не произойдет: это сломало бы почти все существующее программное обеспечение C ++. Если вы посмотрите на некоторую документацию по проектированию комитета C ++, они рассмотрели различные альтернативы, чтобы увидеть, сколько кода он сломает.

Было бы намного проще изменить выражение switch на что-то наполовину умное. Это сломало бы только маленький код. Это все еще не произойдет.

РЕДАКТИРОВАНИЕ ДЛЯ НОВОЙ ИДЕИ:

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

0 голосов
/ 23 августа 2015

Заголовочные файлы являются неотъемлемой частью языка. Без заголовочных файлов все статические библиотеки, динамические библиотеки, практически все предварительно скомпилированные библиотеки становятся бесполезными. Заголовочные файлы также упрощают документирование всего и позволяют просматривать API библиотеки / файла, не просматривая каждый бит кода.

Они также упрощают организацию вашей программы. Да, вы должны постоянно переключаться с источника на заголовок, но они также позволяют вам определять внутренние и частные API внутри реализаций. Например:

MySource.h:

extern int my_library_entry_point(int api_to_use, ...);

MySource.c:

int private_function_that_CANNOT_be_public();

int my_library_entry_point(int api_to_use, ...){
  // [...] Do stuff
}

int private_function_that_CANNOT_be_public() {

}

Если вы #include <MySource.h>, тогда вы получите my_library_entry_point.

Если вы #include <MySource.c>, то вы также получите private_function_that_CANNOT_be_public.

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

0 голосов
/ 22 июля 2010

Тем не менее, я не понимаю смысл некоторых утверждений. Разделение API и реализации - очень хорошая вещь, но заголовочные файлы не являются API. Там есть частные поля. Если вы добавляете или удаляете приватное поле, вы меняете реализацию, а не API.

0 голосов
/ 13 июля 2009

О, да!

После написания кода на Java и C # действительно раздражает иметь 2 файла для каждого класса. Поэтому я подумал, как объединить их, не нарушая существующий код.

На самом деле, это действительно легко. Просто поместите определение (реализацию) в раздел #ifdef и добавьте определение в командную строку компилятора, чтобы скомпилировать этот файл. Вот и все.

Вот пример:

/* File ClassA.cpp */

#ifndef _ClassA_
#define _ClassA_

#include "ClassB.cpp"
#include "InterfaceC.cpp"

class ClassA : public InterfaceC
{
public:
    ClassA(void);
    virtual ~ClassA(void);

    virtual void methodC();

private:
    ClassB b;
};

#endif

#ifdef compiling_ClassA

ClassA::ClassA(void)
{
}

ClassA::~ClassA(void)
{
}

void ClassA::methodC()
{
}

#endif

В командной строке скомпилируйте этот файл с помощью

-D compiling_ClassA

Другие файлы, которые должны включать ClassA, могут просто сделать

#include "ClassA.cpp"

Конечно, добавление определения в командной строке может быть легко добавлено с помощью раскрытия макроса (компилятор Visual Studio) или с помощью автоматических переменных (gnu make) и с использованием той же номенклатуры для имени определения.

0 голосов
/ 16 апреля 2009

Нет языка без заголовочных файлов. Это миф.

Посмотрите на любой проприетарный дистрибутив библиотеки для Java (у меня нет опыта C #, но я ожидаю, что это то же самое). Они не дают вам полный исходный файл; они просто дают вам файл с пустой реализацией каждого метода ({} или {return null;} и т. п.) и всем, что может скрыть скрытое скрытие. Вы не можете назвать это ничем, кроме заголовка.

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

...