Що робити, якщо я ненавиджу файли заголовків C ++?


25

Мене завжди бентежили файли заголовків. Вони такі дивні: ви включаєте .h файл, який не включає .cpp, але .cpp теж якось компілюється.

Нещодавно я приєднався до командного проекту, і, звичайно, використовуються і .h і .cpp.
Я розумію, що це дуже важливо, але я не можу жити, коли копіюємо кожну декларацію функції у кожному з декількох класів.

Як я можу ефективно поводитися з двофакторною умовою?
Чи є інструменти, які допоможуть у цьому, або автоматично змінити один файл, схожий на приклад нижче, на .h та .cpp? (спеціально для MS VC ++ 2010)

class A
{
...
    Type f(Type a,Type b)
    {
        //implementation here, not in another file!
    }
...
};

Type f(Type a)
{
     //implementation here
}
...

8
Це питання може піти двома способами .. "Навіщо нам потрібні заголовки при використанні c ++" або "Чи вважаєте ви, що сучасна мова, яка призначена для складання, повинна використовувати заголовки?" Так, у заголовку є "Що я роблю" та "Ненавиджу", що відзначає безліч прапорів.
Tim Post

4
За вашим запитанням здається, що ви не розумієте C ++ або як компілює його будь-яка система, яку ви використовуєте. Навчіться правильно ним користуватися, а потім задайте більш суб’єктивні запитання.
Девід Торнлі

31
Ваше перше речення вказує на те, що ви "не все розумієте щодо заголовків". Включення .h-файлу не призводить до того, що відповідний .cpp-файл "якось також складений". Ви збираєте .cpp файли самостійно самостійно. Якщо ви не скомпілювали відповідний .cpp, включення заголовка без відповідного об’єктного файлу призведе до виходу з ладу зв’язку.
Пол Різник

5
Що робити? Знайдіть іншу мову, якщо вона вас так клопоче.
Пол Натан

5
Про те, що "не можна жити при копіюванні": Кожен раз, коли оновлюється функція, потрібно оновити всі місця, де вона викликається. Оскільки абонентів набагато важче знайти, ніж декларацію у файлі заголовка, оновлення заголовка - лише незначна деталь.
Sjoerd

Відповіді:


15

Написання ще «Дружнього рефакторингу» C ++

У C ++ взагалі не потрібно використовувати заголовки. Ви можете визначити весь об'єкт в одному файлі так само, як і з C # або Java. Розробники C зазвичай зберігають лише зовнішні дзвінки у файлі заголовка. Усі внутрішні дзвінки визначатимуться у файлі .c. Таким же чином ви можете зарезервувати свої файли C ++ .h для класів / інтерфейсів (чисті віртуальні абстрактні класи) / тощо. які призначені для спільного використання за межами DLL. Для внутрішніх класів / структур / інтерфейсів тощо ви просто включите файл .cpp, який вам потрібен:

#include<myclass.cpp>

Здається, це не найпопулярніший підхід, але це легальний C ++. Це, безумовно, буде можливим для всього вашого внутрішнього коду. Це дозволяє внутрішньому коду та набору класів змінюватися набагато радикальніше, забезпечуючи більш стабільний інтерфейс для коду поза вашою бібліотекою / виконуваним файлом для взаємодії.

Якщо ви будете мати весь клас в одному файлі, ви будете легше робити те, що ви хочете. Це не вирішить проблему перейменування методу та необхідність пошуку в кожному місці, яке називається методом, але це переконається у тому, що у вас з’являться більш розбірливі повідомлення про помилки. Нічого гіршого, ніж заголовок оголосити метод одним способом, але ви реалізуєте його по-іншому. Інший код, який викликає файл заголовка, буде складено належним чином, і ви отримаєте виняток посилання, тоді як файл реалізації буде тим, хто скаржиться, що метод не визначений. Коли ви визначите кожен метод на місці (у фактичному оголошенні класу), ви отримаєте те саме повідомлення про помилку, незалежно від того, який файл включає його.

Ви також можете поглянути на це питання: Хороші інструменти рефакторингу для C ++

Як C / C ++ вирішує файли заголовка / реалізації

На базовому рівні C (і C ++ побудований на цій основі) файли заголовків оголошують обіцянку функції / struct / змінної, якої достатньо, щоб компілятор міг створити файл об'єкта. Аналогічно файли заголовків C ++ оголошують обіцянку функцій, структур, класів тощо. Саме таке визначення компілятор використовує для резервування місця в стеку тощо.

Файли .c або .cpp мають реалізацію. Оскільки компілятор перетворює кожен файл реалізації в об’єктний файл, виникають гачки для нереалізованих понять (що було оголошено у заголовку). Лінкер прив'язує гачки до реалізацій в інших об’єктних файлах і створює більший двійковий файл, який включає весь код (спільна бібліотека або виконуваний файл).

VS Specific

Щодо роботи з тими, хто працює у Visual Studio, є кілька майстрів, які допомагають полегшити справи. Новий майстер класу створить вашу відповідну пару заголовків та файлів реалізації. Існує навіть функція браузера класу, яка дозволить вам оголосити нові методи. Він введе визначення у заголовок та заглушку реалізації у файл .cpp. Візуальна студія мала ці функції більше десяти років (поки я ними користувалася).


Проблема в тому, що я весь час сильно змінюю класи, а не просто додаю нові функції тощо
Олег Припін

5
@BlaXpirit: Отже, чому ти весь час сильно модифікуєш класи? Однією з ідей OO-дизайну є наявність досить стабільних будівельних блоків. Якби я сильно модифікував класи, я хотів би більш динамічну мову, наприклад, Common Lisp або Python.
Девід Торнлі

2
Це я і роблю. Я вдосконалюю / модифікую "будівельні блоки" та додаю нові
Олег Припін

C ++ ніколи не реорганізовував дружніх стосунків. Концепція рефакторингу не набрала обертів, доки не з'явилися інструменти, які зробили це дуже просто зробити в Java IDE. ПРИМІТКА: ці функції існували для розробників Smalltalk та інших мов, але вона не стала мейнстрімом, поки не була доступна для багатьох людей. Поки що я ще не бачив когось розумно реалізувати це для C ++. Можливо, Resharper від JetBrains? Я знаю, що це робить C # і VB-код, але я не впевнений, чи це дасть вам C ++ рефакторинг.
Берін Лорич

@Berin: Я рік-два тому шукав інструменти для рефакторингу C ++ і виявив дві речі. На той час вони були досить дорогими, і я не бачив пробних версій, тому не знаю, що вони зробили. Більше того, один працював лише з emacs, що обмежило б його ефективність у магазині Visual Studio.
Девід Торнлі

13

Стати розробником Java.

Якщо ви дійсно повинні продовжувати розвиватися в C ++, ви можете спробувати використовувати IDE. Часто вони пропонують якийсь механізм, за допомогою якого ви можете додати метод до класу, і він автоматично розміщує декларацію у файлі .h та визначення у файлі .cpp.


2
kthx, я дещо знаю Java, але ти не можеш створити з ним DLL низького рівня, чи не так?
Олег Припін

41
Не знаю чому, але "Стати розробником Java" якось звучить як образа: D.
Олівер Вайлер

2
Якщо ви хочете зробити низький рівень, забудьте про все про "легкі мови". Низький рівень коштує піт і сльози.
Батібікс

5
Не особливо корисна відповідь.
ChrisF

1
@OliverWeiler Я не сприймаю "стати розробником Java" як образу. Я програмую як на C ++, так і на Java, але на сьогоднішній день моїм уподобанням є Java, тому що набагато простіше сісти і вибухнути код, який працює (і більш портативний). Якщо ви чомусь обурюєте існування файлів заголовків, спроба Java може бути правильним вибором (хоча це дивно, ви б ненавиділи файли заголовків; я б розглядав зміну IDE).
Trixie Wolf

7

Вас може зацікавити програма промальовування від Hwaci (тих, хто робить SQLite та Fossil).

Також подивіться, як будується копалина, щоб мати уявлення.


5
Допитуваному все ще потрібно зрозуміти взаємозв’язок між .h та .cpp.
Робота

2
Я розумію основи. Здається, відповідь якраз те, що мені потрібно.
Олег Припін

4

Коли ви пишете перші рядки нового класу, це зазвичай тому, що вам це потрібно в одному місці лише в той час. Згодом він може використовуватися в інших місцях, але спочатку зазвичай це не так.

Багато моїх занять починаються у верхній частині поточного файлу .cpp. Коли він стабілізується достатньо, щоб використовувати його в декількох місцях, я вирізав і вставив його до заголовка. Хоча часто клас зникає так само швидко, як і з’явився.


-1

Як пропозиція допомогти обробляти файли заголовків C ++, звичайно використовувати їх без розширення файлу або суфіксу файлу, як, наприклад, бібліотеки "GCC".

Якщо це у вашому випадку, я пропоную використовувати розширення файлу " .hpp" (або найпростіший " .hxx") або суфікс файлу.

Можливо, вам доведеться налаштувати компілятор, середовище для розробників або вбудовану програму.


3
Ви говорите про те, як при включенні файлу типу #include <iostream>? Це не лише для бібліотеки GCC. Насправді його визначено у стандарті C ++ 1997 року , розділ 17.3.1.2. Я б уникав називати такі файли. Можна, але причиною, що це робила стандартна бібліотека C ++, було те, що це було, щоб уникнути конфліктів імен. Мені здається, це дійсно дивно, коли компілятори автоматично додають ".h", коли ви включаєте заголовок, мені це здається досить нестандартним. І я ніколи не бачу, щоб хтось називав заголовки без суфікса, за винятком стандартної бібліотеки c ++.
vedosity

1
Також слід зазначити, що всі компілятори, якими я користувався, за винятком borland (яких я дуже ненавиджу), не додають автоматично ".h" або ".hpp" або ".hxx" при спробі включити файл без суфікса. Не сподівайтеся, що #include <someclass>він буде прочитаний як #include <someclass.hpp>у всіх компіляторах. Ваш код зламається.
vedosity
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.