Declaration vs. Definition

В обсуждении о спецификации классов, термин "definition" ("определение") был использован относительно функции. Когда мы "definition" функцию, мы определяем поведение функции посредством кода, который записан в пределах фигурных скобок. "Декларация" функции, с другой стороны, только определяет интерфейс функции. Этот интерфейс включает название функции, возвращаемый тип, и список параметров и их типов. Следующая распечатка показывает и декларацию и определение среднего числа функции.

1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: #include <iostream>#include <cstdlib> using namespace std; // function declarationdouble average(int, int); int main(int argc, char* argv[]) { cout << average(10, 2) << endl; return EXIT_SUCCESS;} // function definitiondouble average(int total, int count) { return (total / count);}
Listing 6 Declaration vs. definition

Декларация и определение функции отличаются по многим аспектам. В вышеприведенном примере декларация среднего числа функции сопровождается точкой запятой а не фигурными скобками. Это и есть декларация (не определение). Декларация функции не должна включать имена переменной для параметров. Интересно отметить, что определение функции находится после ее фактического использования в главной функции. Такое вполне допустимо. Такая практика распространена в C++ программировании. Однако, так недопустимо для использования функции или класса, которые еще не определены.

 

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

 

Программисты должны полностью квалифицировать названия функций члена класса, которые появляются за пределами определения класса. Чтобы квалифицировать название полностью, название функции должно предварительно быть на рассмотрении с названием класса, сопровождаемым scope resolution operator (::). Listing 7 определяет функции участника класса вне определения класса.

1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: class BankAccount { private: double sum; string name; public: BankAccount(string nm) : name(nm), sum(0) {} BankAccount(string nm, double bal) : name(nm), sum(bal) {} double balance(); void deposit(double); void withdraw(double); string getName();}; double BankAccount::balance() { return sum;}void BankAccount::deposit(double amount) { sum += amount;}void BankAccount::withdraw(double amount) { sum -= amount;}string BankAccount::getName() { return name;}
Listing 7 Defining class member functions outside the declaration

 

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

Отделение участника возможно из их деклараций, т.к. позволяют разделение предварительно оттранслированной программы. Listing 7 показывает определения функции членов класса, которые появляются вне их определения класса. Определения функции участника класса могут также появиться и в другом файле чем определение класса. Когда программист определяет класс, можно собрать файл, который содержит определения функции члена класса. Этот файл, содержащий определения функции члена класса, известен как файл выполнения. Файл определения класса (или header файл) подключается интерфейсом в предварительно собранном коде.

Listing 8 показывает файл определения bankaccount.h:

1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: #include <string>#include <cstdlib>#include <iostream> #ifndef _BANKACCOUNT_H#define _BANKACCOUNT_H using namespace std; class BankAccount { private: double sum; string name; public: BankAccount(string nm) : name(nm), sum(0) {} BankAccount(string nm, double bal) : name(nm), sum(bal) {} double balance(); void deposit(double); void withdraw(double); string getName();}; #endif
Listing 8 bankaccount.h

 

Распечатка 9 показывает файл выполнения bankaccount.cpp:

1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: #include "bankaccount.h" double BankAccount::balance() { return sum;}void BankAccount::deposit(double amount) { sum += amount;}void BankAccount::withdraw(double amount) { sum -= amount;}string BankAccount::getName() { return name;}
Listing 9 bankaccount.cpp

Директива препроцессора #include, заменяют директиву содержанием указанного файла. Директивы #define, #ifndef и #endif, если используются, чтобы проверить, не включен ли файл определения несколько раз. Мы исследуем использование директив препроцессора в 1.3.4 The Preprocessor.