Pull to refresh

Тонкости реализации кода библиотеки. Часть первая

Reading time2 min
Views6K
При написании библиотеки на C++ многие сталкиваются с определенными трудностями при написании и организации кода. У некоторых уже есть готовые решения, у других их нет и они пытаются найти эти решения.

Некоторые трудности при написании кода библиотеки, в большей степени касающиеся «самодокументирования», можно решить с помощью «рабочих» пространств имен.

Для начала, опишем эти трудности и представим обычные способы решения.

Предположим, что библиотека реализует некоторую сущность some_class, которую она предоставляет пользователю библиотеки. Определение some_class зависит от другой сущности библиотеки detail_class, которая является частью реализации и пользователю не предоставляется. Библиотека поставляется только в виде заголовочных файлов.

Распределение кода по файлам в данном топике не рассматривается.

Стандартное решение 1


namespace lib_namespace
{
    class detail_class
    {
    };

    class some_class
    {
    public:
        // открытый интерфейс
    private:
        detail_class a_;
        // другие члены класса
    };
}


Плюс данного решения:
1) минимальное количество кода, необходимого для его реализации.

Минусы:
1) Плохое «самодокументирование» кода. Не всегда по имени классов реализации в данном случае можно определить пользовательские они или нет.
2) Захламление пространства имен библиотеки. Некоторые среды разработки при использовании данного пространства имен, будут отображать то, что пользователю библиотеки не нужно:



Стандартное решение 2


namespace lib_namespace {
namespace impl
{
    class detail_class
    {
    };
}}

namespace lib_namespace
{
    class some_class
    {
    public:
        // открытый интерфейс
    private:
        impl::detail_class a_;
        // другие члены класса
    };
}

Данное решение полностью убирает недостатки предыдущего подхода, но добавляет свои:
1) введение дополнительного пространства имен;
2) В любом библиотечном классе, предоставляемом пользователю и размещенном в lib_namespace, необходимо для всех элементов реализации указывать префикс impl::.

Достоинства:
1) хорошее «самодокументирование» кода.

Решение на основе «рабочих» пространств имен


namespace work_lib_namespace
{
    class detail_class
    {
    };

    class some_class
    {
    public:
        // открытый интерфейс
    private:
        detail_class a_;
        // другие члены класса
    };
}

namespace lib_namespace
{
    using ::work_lib_namespace::some_class;
}


Весь код библиотеки размещается в рабочем пространстве имен work_lib_namespace. Все сущности, которые библиотека предоставляет пользователю, добавляются в основное пространство имен библиотеки посредством using.

Недостаток данного подхода:
1) введение дополнительного пространства имен.

Достоинства:
1) «самодокументирование» кода;
2) возможность использования using namespace some_ns внутри рабочего пространства имен (даже в тех заголовочных файлах библиотеки, которые пользователь непосредственно подключает):


namespace work_lib_namespace
{
    using namespace std;

    class detail_class
    {
    public:
        // интерфейс
    private:
        vector<int> data_;
    };
}


Заключение


Представленный способ организации библиотеки позволяет с одной стороны добиться хорошего «самодокументирования» кода, а с другой — позволить разработчикам библиотеки использовать using namespace не только в файлах реализации сpp, но и в заголовочных файлах.
Tags:
Hubs:
Total votes 30: ↑24 and ↓6+18
Comments30

Articles