Возможно, это не настоящий вопрос, закройте его, если он не подходит.
В C ++ нельзя смешивать заголовок и реализацию в одном исходном файле, например, класс будет определен дважды, если он включен в a.cc
и b.cc
:
// foo.h
#pragma once
class Foo {
void bar() { ... }
};
// a.cc
#include "foo.h"
class A {};
// b.cc
#include "foo.h"
class B {};
// Link all
$ gcc -c -o a.o a.cc
$ gcc -c -o b.o b.cc
$ gcc -o main main.cc foo.o a.o b.o
Тогда это неоднозначно Foo :: bar () в трех объектных файлах!
Вместо этого мы должны разделить реализацию в другой файл:
// foo.h
#pragma once
class Foo {
void bar();
};
// foo.cc
# include "foo.h"
void Foo::bar() { ... }
Хотя, возможно, это и не большая проблема, потому что обычно двоичные выражения для foo :: bar () в a.o
и b.o
совпадают. Но, по крайней мере, есть несколько лишних объявлений, не так ли? И еще некоторые беспорядки, вызванные этим избыточным:
Где указать значения по умолчанию для необязательных параметров?
class Foo {
void bar(int x = 100);
};
или
void Foo::bar(int x = 100) { ... }
или оба?
Перемещение между встроенными и не встроенными ...?
Если вы хотите переключить не встроенную функцию на встроенную, вы должны переместить код с foo.cc
на foo.h
и добавить префикс ключевого слова inline
. И, может быть, через две секунды вы сожалеете о том, что сделали, затем вы перемещаете встроенный элемент в foo.h
обратно в foo.cc
и снова удаляете ключевое слово inline
.
Но вам не нужно будет делать это, если декларация и определение находятся вместе.
И таких мелких головных болей больше.
Идея состоит в том, что если вы напишите определение функции вместе с объявлением, то компилятор не сможет вывести прототип функции.
Например, используя один source.cc
и импортировать только информацию о типе, например,
#include_typedef "source.cc"
Все будет проще. Компилятору легко игнорировать распределение переменных и определения функций, просто фильтруя их во время синтаксического анализа, даже до создания AST, не так ли?
Я привык к программированию в отдельных файлах исходного кода / заголовка, я, безусловно, способен выполнять разделение. Вы можете поспорить о стиле программирования, но это снизит вопрос о том, как правильно представлять логику, а о том, какой стиль программирования лучше. Я не думаю, что Java - лучший стиль программирования в контексте разделения заголовка и источника. но Java дает правильный путь.
Вы не возражаете отделить заголовки от классов?
Если возможно, как вы будете смешивать их в один?
Есть ли C ++ front-end, который может отделить объявление и определение в отдельные файлы из смешанных источников? Или как я могу написать такой? (Я имею в виду GCC.)
EDIT
В любом случае, я не ругаю C ++, извините, если вы получили неверную информацию из этого вопроса.
Поскольку C ++ является мультипарадигмальным языком, вы можете увидеть, как MFC устанавливает привязку сообщений с помощью магических макросов, и как библиотека boost реализует все, используя шаблоны. Когда разделение переходит в проблемную область (благодаря тому, что ONeal указывает, что домен принадлежит системе упаковки), можно попытаться выяснить, как его решить. Для меня так много стилей программирования, потому что я потратил так много времени на программирование на C ++, поэтому любое маленькое удобство накапливается в большое удобство. Реализация записи вместе с декларацией является одной из удобных. Я думаю, я могу уменьшить исходные строки по крайней мере на 10%, если мне не нужно разделять их. Вы можете спросить, если удобство так важно, почему бы просто не использовать Java? Очевидно, что C ++ отличается от Java, они не взаимозаменяемы.
Встроенная функция может решить проблему, но она вообще меняет семантику.