Що таке forward declaration, arm, programming

В теорії програмування термін forward declaration означає декларування ідентифікатора (що означає такий об'єкт, як тип, змінна або функція) до того, як програміст дав йому повне визначення. Це потрібно для того, щоб компілятор знав тип ідентифікатора (щоб можна було визначити необхідний розмір пам'яті для створення об'єкта, для перевірки типу або підпису функції), при цьому необов'язково ідентифікатор може містити значення (в разі змінної). Це також корисно для однопрохідних компіляторів. Forward declaration використовується в мовах, які вимагають декларування об'єкта перед його використанням (мови C, C ++); це необхідно в таких мовах для взаємної рекурсії (mutual recursion), оскільки неможливо визначити ці функції без посилання вперед в одному визначенні. Це також корисно для того, щоб наочно організувати структуру коду, наприклад якщо Ви хочете розмістити основну, головну частину коду в верхній частині модуля, і нижче все що викликаються з цієї головної частини функції.

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

Давайте розглянемо базовий приклад попереднього декларування функції на мові C:

На мовах C / C ++ це декларування представляє forward declaration функції, і це так званий прототип функції. Після обробки цієї декларації компілятор дозволяє програмісту посилатися на об'єкт printThisInteger в іншій частині програми (яка йде в тексті модуля за forward declaration функції printThisInteger, або взагалі в іншому модулі). Щоб програма була працездатна, визначення для функції все одно має бути десь надано (в тому ж самому файлі модуля, або в іншому - не важливо, це вже обов'язок линкера правильно поставити відповідність посилань для окремої функції в одному або декількох об'єктних файлах на визначення цієї функції):

Змінні можуть мати тільки попереднє декларування, без наявності визначення. Під час компіляції коду вони будуть ініційовані за спеціальними правилами мови (в невизначені значення, 0, покажчики NULL.). Змінні, які визначені в іншому вихідному модулі (і відповідно з'являться після компіляції в іншому об'єктному файлі), повинні мати forward declaration, представлену з ключовим словом extern (для функцій це ключове слово використовувати необов'язково):

У Pascal та інших Віртовскіх мовах програмування, головне правило говорить: все сутності повинні бути декларовані перед використанням, так що потрібно використовувати forward declaration, що необхідно, наприклад, для взаємної рекурсії (mutual recursion). Мовою C це головне правило теж працює, але тут є виняток для невизначених функцій і незавершених типів. Таким чином, на C можна (хоча і небажано) реалізувати пару взаємно рекурсивних функцій:

У Pascal та ж сама реалізація вимагає forward declaration для другої функції, щоб вона могла використовуватися в першій. Без наявності такої forward declaration компілятор видасть помилку, що повідомляє про те, що другий ідентифікатор використовується до того, як він був визначений.

На деяких об'єктно дез орієнтованих мовах зразок C ++ і Objective-C, іноді потрібно застосувати попереднє декларування для класів (forward declare class). Це відбувається в ситуаціях, коли потрібно знати, що ім'я класу - тип (але для структури це знати не потрібно).

Мовою C ++ класи і структури можуть бути forward-declared приблизно так:

Мовою C ++ класи можуть бути forward-declared, якщо тільки Вам потрібно використовувати тип покажчика на цей клас (оскільки всі покажчики на об'єкти мають однаковий розмір, і про це повинен подбати компілятор). Особливо це корисно всередині визначень класу, наприклад якщо клас містить у собі член, який є указиваетeлем на інший клас; щоб уникнути циклічних посилань (наприклад, цей клас може також містити член, який вказує на цей же клас), ми просто замість цього робимо попереднє декларування класів.

Forward declaration для класу недостатньо, якщо Вам потрібно використовувати дійсний тип класу. Наприклад, якщо Ви маєте член класу, який має тип не покажчика, а безпосередньо задає клас, або якщо Ви використовуєте його як базовий клас, або якщо Вам потрібно використовувати методи цього класу в іншому методі.

Мовою Objective-C класи і протоколи можуть бути forward-declared приблизно так:

Мовою Objective-C класи і протоколи можуть бути forward-declared, якщо тільки Вам потрібно використовувати їх як частину типу покажчика на об'єкт, наприклад MyClass * або id . Це особливо корисно всередині визначень класу, наприклад якщо клас містить члени, які є покажчиками на інші класи; щоб уникнути циклічних посилань (наприклад, цей клас може також містити член, який вказує на цей же клас), ми просто замість цього робимо попереднє декларування класів.

Застосовувати forward declaration для класу або протоколу недостатньо, якщо Вам потрібен підклас subclass цього класу, або якщо треба реалізувати цей протокол.

Приклад (допустимої) forward reference на мові C ++:

У цьому прикладі є два посилання на myValue до того, як ця змінна була визначена. C ++ головним чином забороняє застосовувати forward reference, але це дозволено в спеціальному випадку для членів класу. Оскільки функція член класу accessor не може бути скомпільована, поки компілятор не впізнає тип члена класу змінної myValue, то це обов'язок компілятора пам'ятати визначення accessor, поки він не побачить декларацію myValue.

Дозвіл використання forward reference може значно ускладнити компіляцію і збільшити вимоги до пам'яті з боку компілятора, і це звичайно не дає реалізувати компіляція за один прохід.

1. Forward declaration site: en.wikipedia.org.