C ++: развязка интерфейса / реализации без использования виртуальных функций? - PullRequest
4 голосов
/ 23 декабря 2009

Я был избалован использованием Java в последние несколько месяцев! У меня есть проект C ++, где я хотел бы отделить интерфейс класса (файл .h) от деталей его реализации. Но поля-члены класса должны быть в его объявлении, и, похоже, у меня есть эта неизбежная связь зависимостей, если я хочу настроить поля-члены класса.

Я знаю, что один из способов сделать это - использовать полиморфизм + наследование классов (сделать интерфейс базовым классом, сделать реализацию производным классом), но если я правильно помню, для этого требуются виртуальные функции, которые я бы хотел избегайте - это на DSP, и с вещами выгодно не слишком "C ++ -y".

есть предложения?

Ответы [ 4 ]

12 голосов
/ 23 декабря 2009

Вы хотите использовать PIMPL .

2 голосов
/ 23 декабря 2009

Знаешь, я думал об этом и о твоем возражении против PIMPL.

У меня ужасный хак, который я иногда использую в таких случаях, когда я возмущаюсь, платя штраф за косвенное обращение. Хотя обычно моя жалоба связана с вызовом нового, а не с разыменованием указателя. Я представляю свой уродливый взлом таким образом:

//  IHaveOpaqueData.h

class IHaveOpaqueData {
 public:
    // To make sure there are no alignment problems, maybe ::std::uin64_t
    typedef maximally_aligned_type_t internal_data_t[32];  // Some size I hope is big enough

    void iCanHazMemberFunction();
    // ...
 private:
    internal_data_t data;
};

//  IHaveOpaqueData.cpp
#include <boost/static_assert.hpp>

namespace { // Hide it in an anonymous namespace
struct RealData {
    int icanhazmembervariable_;
    double icanhazdoublevariable_;
};
BOOST_STATIC_ASSERT(sizeof(RealData) < sizeof(IHaveOpaqueData::internal_data_t);
}

void IHaveOpaqueData::iCanHazMemberFunction()
{
    // Use a reference to help the optimize make the right decision
    RealData &datathis = *(reinterpret_cast<RealData *>(&(this->data)));
    datathis.icanhazmembervariable_ = datathis.icanhazdoublevariable_;
}

Да, это безобразно. BOOST_STATIC_ASSERT (или, если у вас есть компилятор C ++ [01] x, ключевое слово static_assert) помогает сделать это не полной катастрофой. Может быть разумный способ использовать профсоюзы для смягчения некоторых проблем, связанных с выравниванием, которые у меня есть.

1 голос
/ 23 декабря 2009

Используйте идиому pimpl. Читайте здесь: http://www.devx.com/cplus/Article/28105/0/page/3

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

0 голосов
/ 23 декабря 2009

Вот старая идея :) - непрозрачный тип данных плюс набор функций, то есть «туда и обратно [в C] снова»:


// oi.hpp
namespace oi // old idea
{
    struct opaque; // forward declaration

    void init( opaque& ); // ctor
    void fini( opaque& ); // dtor

    int get_foo( const opaque& ); // getter
    void set_foo( opaque&, int ); // setter
}
// oi.cpp
namespace oi
{
    struct opaque // definition
    {
        int foo_; // data members
        // ...
    };

    // function definitions
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...