2009-12-23 2 views
4

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

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

любые предложения?

+4

Я бы сказал, что более «ошибочно» тогда «испорчено» :) - в Java все виртуально, если не отмечено «final». –

+1

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

+0

Изучение Java на самом деле улучшило мои навыки разработки и кодирования на C++. –

ответ

12

Вы хотите PIMPL idiom.

+0

Это имя по-прежнему немного дрожит , но я все еще собирался опубликовать то же самое. +1 –

+0

Link plz. Kthx bye. –

+0

Не будет ли проходить через pimpl/bridge эквивалентно дополнительной разыгрыванию через таблицу vtable? –

2

Знаете, я подумал об этом и о вашем возражении против 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), это не делает его полной катастрофой. Может быть умный способ использовать союзы для смягчения некоторых из подергиваний, которые у меня возникают по вопросам выравнивания.

+0

Уродство - это преуменьшение. Если объект долгоживущий, то цена нового для внутреннего datastruct лучше этого. Если он недолговечен, то, возможно, оптимизированный распределитель пулов для этого типа объекта. Или просто живите с некоторым дополнительным временем компиляции, я бы предпочел заплатить за это, чем ввести код, похожий на этот или основной эффект выполнения! – tim

+0

Полное обсуждение см. По адресу http://www.gotw.ca/gotw/028.htm «Идиома Fast Pimpl». И хотя это страшно, я написал шаблонную версию того, что сделал Omnifarious, чтобы сделать ее более безопасной и удобной. Тем не менее, все еще страшно. – tony

+0

У этого есть преимущество безопасности потока над быстрым прыщи. Обеспечение быстрой защиты от прыщей нить безопасно убивает большую часть своей скорости. Мой взлом становится очень сложным и чрезвычайно подверженным ошибкам, когда содержимое внутренней структуры данных не является POD. – Omnifarious

0

Вот старая идея :) - непрозрачный тип данных плюс набор функций, т.е. «туда и обратно [в 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, не могут быть использованы.

1

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

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

Смежные вопросы