С++: сокрытие деталей реализации класса универсального


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

Я нашел этот сайт, который описывает, как скрыть реализацию деталь в C++: http://www.octopull.demon.co.uk/c++/implementation_hiding.html

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

#define TL_UTILS_IMPL_DECL(member) \
    private: \
        class impl; \
        impl* member;

#define TL_UTILS_IMPL_START(t_class, parent) \
    class t_class::impl \
    { \
        public: \
            t_class* parent; \
            impl(t_class* self) \
                : parent(self) \
            {}

#define TL_UTILS_IMPL_END() \
    };

#define TL_UTILS_IMPL_INIT(member) \
    member = new impl(this);

#define TL_UTILS_IMPL_TERM(member) \
    delete member;

#define TL_UTILS_IMPL_PREFIX(t_class) \
    t_class::impl::

Пример использования:

// Header file:
    class foo
    {
            TL_UTILS_IMPL_DECL(m)

        public:
            foo();
            ~foo();
    };

// Source file:
    TL_UTILS_IMPL_START(foo, p)
        void bar();
    TL_UTILS_IMPL_END()

    foo::foo()
    {
        TL_UTILS_IMPL_INIT(m)

        // from here on we can use the private
        // data and methods stored in m
        m->bar();
    }

    foo::~for()
    {
        TL_UTILS_IMPL_TERM(m)
    }

    void TL_UTILS_IMPL_PREFIX(foo) bar()
    {
        // do something useful
        // use p as a pointer to the parent class instance
    }

Я всегда слышу, что макросы препроцессора грязные и не должна быть использована в C++, и я согласен в некоторой степени. Однако я не мог понять, что я хотел, используя шаблоны.

Так что вы думаете?

  • Использование препроцессора макросов оправдано здесь?
  • Это безопасный код?
  • Любые улучшения, которые вы можете думать?


2636
3
c++
задан 4 октября 2011 в 11:10 Источник Поделиться
Комментарии
3 ответа

Я, конечно, сочувствую вам об увеличении времени сборки. Проект C++ в настоящее время я работаю на занимает 45 - 60 минут, чтобы построить с нуля. Но эти макросы не читаются. Когда я вижу их глаза стекленеют, и я даже не хочу пытаться понять, что ты делаешь.

пустота TL_UTILS_IMPL_PREFIX(ФОО) бар()

Эта линия, в частности, несносный. Это выглядит некрасиво, это вообще не изначально ясно, зачем ты это делаешь, а когда разработчик делает это выяснить, наверное, разозлить их! =)

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


  1. Разделить приложение на несколько небольших конкретных dll файлы.

  2. Не подвергайте бетона классов от вас файлов. Вместо этого, ваши конкретные классы, реализующие интерфейсы, и скомпилировать против этих интерфейсов из другой DLL/EXE-файлы.

Проверьте это статьи с CodeProject. Под заголовком, зрелый подход: используя абстрактный интерфейс, подробное объяснение пункта 2.

Конечным результатом этих двух изменений состоит в том, что все ваши dll файлы смогут составить независимо друг от друга. Если вы держите их маленькие и сосредоточены, стоимость перекомпиляции пару файлов внутри библиотеки DLL не является слишком высокой.

В противном случае, если вы действительно хотите использовать интеллекту, просто напишите код. Не хороните ее в уродливые макросы.

2
ответ дан 6 октября 2011 в 05:10 Источник Поделиться


Использование препроцессора макросов оправдано здесь?

Мне кажется, как Overkill. Единственный нетривиальный макрос TL_UTILS_IMPL_START, и что почти наверняка никогда не пригодится - как правило, осущ класса не нужна-указатель на класс-оболочку, но будут нужны другие аргументы конструктора, так что вы будете иметь, чтобы написать свой собственный класс-специфических конструктора и инициализации тестов в любом случае. Другие макросы так же болтлив, как и гораздо менее очевидны, чем их заменить.


Это безопасный код?

Необходимо применить "правило трех" - либо реализовать, или удалить конструктор копирования и копирующий оператор присваивания. Я вообще использовать импульс::scoped_ptr для осуществления указатель, который сортирует это для меня (а также устраняя необходимость деструктор тела).

3
ответ дан 4 октября 2011 в 01:10 Источник Поделиться


Это всегда беспокоило меня, что вам придется написать свой собственный класс
члены внутри заголовочных файлов в C++.

Это является частью хорошей практики программирования. При реализации этих макросов (и я согласен с @MikeSeymour, что это перебор), вы помните, что вы думаете сейчас, но через пару месяцев вы будете иметь ни малейшего понятия, о чем ты думаешь. Кроме того, что сразу видно, для вас, может не быть на другое лицо. Если другой человек может не понять ваш код или приходится тратить время на расшифровку его, что просто вызывает головную боль и увеличивает время разработки. Если у вас есть веская причина (и прослушивается не один из них), вы действительно должны объявить закрытым членам в заголовке.


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

Если вы ориентированы на универсального кода, интерфейсы/шаблоны будут более подходящими, чем класс. Если вы все же хотите использовать ООП, учитывая, используя полиморфизм или наследование. Используя эти две функции ООП, вы сможете поддерживать универсальный класс и хорошая практика программирования. Это также поможет сохранить ваш код безопасным и грамотно управлять областью.

0
ответ дан 4 октября 2011 в 01:10 Источник Поделиться