Директивы #ifndef и #endif

Рассмотрим пример программы из раздела Классы в С++. Программа использует простейший класс, объект которого печатает сообщение. Заметьте, что раньше класс был объявлен в одном файле с главной функцией, но такой способ утилизации классов не эффективен, почему, было рассмотрено в разделе Классы в С++. Так вот, теперь объявление класса находится в файле message.h , а реализация методов класса определена в  файле message.cpp, а classes.cpp — файл с main() функцией.

// интерфейс класса, файл: message.h
class CppStudio // имя класса
{
public: // спецификатор доступа
    void message(); // функция (метод класса) выводящая сообщение на экран
}; // конец объявления класса CppStudio

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

// реализация класса CppStudio, файл: message.cpp
#include "stdafx.h"
// связываем интерфейс класса с его реализацией
#include "message.h"
// подключаем прототип оператора cout
#include <iostream>

void CppStudio::message() // функция (метод класса) выводящая сообщение на экран
{
    std::cout << "website: cppstudio.com\ntheme: Classes and Objects in C + +\n";
}

Реализация данного класса включает в себя всего один метод, который печатает сообщение.

// classes.cpp: определяет точку входа для консольного приложения.

#include "stdafx.h"
#include <iostream>
using namespace std;

#include "message.h"

int main(int argc, char* argv[])
{
    CppStudio objMessage; // объявление объекта 
    objMessage.message(); // вызов функции класса message
    system("pause");
    return 0;
}

// код Code::Blocks

// код Dev-C++

// classes.cpp: определяет точку входа для консольного приложения.

#include <iostream>
using namespace std;

#include "message.h"

int main(int argc, char* argv[])
{
    CppStudio objMessage; // объявление объекта
    objMessage.message(); // вызов функции класса message
    return 0;
}


Структура данной программы совсем простая, чего не скажешь о программах с большим объёмом кода. В таких программах, как правило, код расположен не в одном файле. И подключение заголовочных файлов выполняется не обязательно в главном файле. Поэтому существует вероятность многократного включения в программу заголовочного файла, что в свою очередь приводит к ошибке компиляции.  В случае с нашей программой, заголовочный файл подключен в главном файле в строке 7 и программа нормально работает без всяких ошибок. А если же заголовочный файл message.h, по ошибке,  был подключён  не только в главном файле программы, но, и ,например, в файле stdafx.h. В таком случае при компиляции программы появится следующая ошибка:

//Ошибка  1  error C2011: CppStudio: переопределение типа "class"

То есть, компилятор сообщает о многократном включении заголовочного файла с классом CppStudio. В таком случае придется потратить своё время и убрать лишнее включение в программу заголовочного файла. Чтобы не возникало такого рода ошибок, в С++ существует специальная структура кода, которую ещё называют препроцессорная обёртка.

// препроцессорная обёртка, файл: message.h с интерфейсом класса

#ifndef CPPSTUDIO_H    // если имя CPPSTUDIO_H ещё не определено
#define CPPSTUDIO_H   // определить имя CPPSTUDIO_H

// определить класс CPPSTUDIO_H
class CppStudio // имя класса
{
public: // спецификатор доступа
    void message(); // функция (метод класса) выводящая сообщение на экран
}; // конец объявления класса CppStudio 

#endif CPPSTUDIO_H     // если  имя CPPSTUDIO_H уже определено, повторно не определять

Данная препроцессорная обёртка предотвращает попытку многократного включения заголовочных файлов. Препроцессорные директивы обрабатываются до этапа компиляции, программой-препроцессором. Который, в свою очередь не допускает многократного определения одного и того же класса. Препроцессорная обёртка похожа на оператор условного выбора if. Директива #ifndef проверяет, определено ли имя CPPSTUDIO_H, если нет, то управление передаётся директиве #define и определяется интерфейс класса. Если же имя CPPSTUDIO_H уже определено, управление передаётся директиве #endif. Таким образом, исключается возможность многократного определения класса CPPSTUDIO_H.
Обратите внимание на то, как написано имя класса, используемое в сочетании с директивами препроцессорной обёртки — CPPSTUDIO_H. Берётся имя заголовочного файла, в котором объявлен класс, причём имя принято записывать буквами верхнего регистра, а вместо точки ставить символ нижнего подчёркивания. Конечно же, имя может быть любым другим, но оно должно быть одинаковым во всех трёх директивах. Итак, структура препроцессорной обёртки такова:

// структура препроцессорной обёртки

#ifndef /*ИМЯ ЗАГОЛОВОЧНОГО ФАЙЛА_H*/
#define /*ИМЯ ЗАГОЛОВОЧНОГО ФАЙЛА_H*/

// определение класса

#endif /*ИМЯ ЗАГОЛОВОЧНОГО ФАЙЛА_H*/

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

Практика

К сожалению, для данной темы пока нет подходящих задач. Если у вас есть таковые на примете, отправте их по адресу: admin@cppstudio.com. Мы их опубликуем!

Автор: admin
Дата: 25.08.2012
Поделиться:

Комментарии

  1. Vaidokcrunk

    Vaidokcrunk

    Заказать Сиалис в РФ

    Даже если взрослый мужик придерживается здорового образа жизни, ежегодно проходит все обследования и бегает по утрам, рано или поздно его все-равно поджидают трудности с потенцией: такова неприятная суть старения.

    К большому счастью современная медицина создала [url=http://via-sexgra.ru/levitra-kupit-moskva]дженерик левитра отзывы[/url] , которые смогут продлить здоровую интимную жизнь на полтора десятка лет, не причиняя вреда при этом здоровью всех других органов и систем. Речь идет о Виагре дженериках, что вы можете заказать на этом портале via-sexgra.ru

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

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

  2. Denya Lorents

    Возможно эту статью следует переставить на чуть более ранний этап обучения? Где-то ближе к вынесению функции в отдельный файл.

  3. Илья Бологан

    а не проще с помощью

    #pragma once
    • eagle_vik

      eagle_vik

      Илья, можно и

      #pragma once

      , но учти что это работает только на Windows-платформах! Если ты будешь кодить под Unix системы, то там эту директиву не распознает, и она просто работать не будет!

Оставить комментарий

Вы должны войти, чтобы оставить комментарий.