Всех приветствую есть класс пример Код (Text): class someclass{ ...backgroundworker(); public: ...foregroundworker(); }; backgroundworker это служебная функция помогающая в реализации паблик методов типа клиентам вообще ее лучше не видеть но так как она внутри обращается к приват полям то пришлось тащить ее в интерфейс как приват член можно конечно описать как friend но все равно ее будет видно клиентам хочется чтоб про нее вообще не знали как сделать ? думал сделать паблик метод меняюший приват поля и внутри backgroundworker использовать его тогда backgroundworker можно было бы из интерфейса выкинуть но тогда появился бы новый костыль в интерфейсе и любой кому не лень этот паблик интерфейс заюзает и изменит приват поля вообщем незнаю жду ваших советов ... хочется чтоб backgroundworker была простой функцией имеющей доступ к приват полям и чтоб в описании интерфейса класса о ней вообще не упоминалось
Сделать интерфейс, который будете предоставлять клиентам, а в реализации городить можно что угодно. Клиенты должны использовать интерфейс, реализацию они видеть не должны Код (Text): struct ISomeClass { foregroundworker(); static ISomeClass* CreateSomeClass(...) { return new CSomeClass(...) } } class CSomeClass : public ISomeClass { ...backgroundworker(); public: ...foregroundworker(); };
... здесь было много плохих слов ... [modnote=TermoSINteZ]Предупреждение. Еще раз и в бан. Уважайте участников форума.[/modnote]
osox Тебе пояснили уже "pimpl" , то что ты хочешь это и идиома называется "Pointer to implementation". можно так: lib1.hpp: Код (Text): class MySuperPuperLib { public: MySuperPuperLib(); ~MySuperPuperLib(); private: class MySuperPuperLibHelper; typedef std::auto_ptr<MySuperPuperLibHelper> MySuperPuperLibHelperPtr_t; MySuperPuperLibHelperPtr_t _helper; }; lib1.cpp: Код (Text): #include <std.hpp> class MySuperPuperLib::MySuperPuperLibHelper { // тут кишки хэлпера }; MySuperPuperLib::MySuperPuperLib() : _helper(new MySuperPuperLibHelper) { } MySuperPuperLib::~MySuperPuperLib() { } примерно как-то так. главная мысль "деструктор и конструктор основного класса, должны видеть декларацию класса-хелпера, иначе как им знать как создавать и как убивать?"
а так нормально ? файл интерфейса yyk.h Код (Text): class someclass{ int fd; public: void foregroundworker(); }; файл реализации yyk.cpp Код (Text): class someclass{ int fd; void backgroundworker(int c){fd=c;} public: void foregroundworker(); }; void someclass::foregroundworker(){ this->backgroundworker(0x111); } драйвер main.cpp Код (Text): #include "yyk.h" int main(){ someclass o; o.foregroundworker(); } вроде то что нужно можно ли так ? делает оно то что мне нужно но это не похоже на pimpl
угу а знаеш почему ? потому что среди них ты один мудaк [modnote=Great]А ведь предупреждали.([/modnote]
общий смысл таков ? lib.h Код (Text): class sc{ class hlp; hlp *p; public: int pub; sc(int c); ~sc(); void print(); }; lib.cpp Код (Text): #include "lib.h" class sc::hlp{ public: hlp(int c):f(c){} int f; void back(sc *r){ puts("back"); this->f = 789; r->pub = 890; } }; sc::sc(int c):p(new hlp(c)){} sc::~sc(){delete p;} void sc::print(){ printf("%x\n", this->p->f); this->p->back(this); } main.cpp Код (Text): #include "lib.h" int main(){ sc c(0x777); c.print(); }
А ещё можно так. .H файл: Код (Text): struct tag_TDATACLASS_MEMBERS; class TDataClass { public: TDataClass (); virtual ~TDataClass (); // // Interface for consumer of this object // HRESULT PerformAction1 (); HRESULT PerformAction2 (); HRESULT PerformAction3 (); private: tag_TDATACLASS_MEMBERS* m_pMembers; }; .CPP файл: Код (Text): #include <windows.h> #include "TDataClass.h" typedef struct tag_TDATACLASS_MEMBERS { HANDLE Handle; UINT Flags; WCHAR Path [MAX_PATH]; } TDATACLASS_MEMBERS; static int _Helper1 (TDATACLASS_MEMBERS& data); static int _Helper2 (TDATACLASS_MEMBERS& data); static int _Helper3 (TDATACLASS_MEMBERS& data); TDataClass::TDataClass () { m_pMembers = (TDATACLASS_MEMBERS*) calloc (1, sizeof (TDATACLASS_MEMBERS)); } TDataClass::~TDataClass () { free (m_pMembers); } static int _Helper1 (TDATACLASS_MEMBERS& data) { if (data.Flags & 1) { _Helper3 (data); } return 0; } static int _Helper2 (TDATACLASS_MEMBERS& data) { data.Handle = ::HeapCreate (0, 0, 0); return 0; } static int _Helper3 (TDATACLASS_MEMBERS& data) { ::SetCurrentDirectory (data.Path); return 0; } HRESULT TDataClass::PerformAction1 () { //... _Helper1 (*m_pMembers); //... return 0; } HRESULT TDataClass::PerformAction2 () { //... _Helper2 (*m_pMembers); //... return 0; } HRESULT TDataClass::PerformAction3 () { //... _Helper3 (*m_pMembers); //... return 0; } Удобно для сохранения/восстановления данных класса - одна операция чтения/записи на всю структуру вместо по-элементного доступа. Минус: достать данные из адреса требует дополнительной загрузки регистра -- хотя зависит от компилятора. Полностью оптимизированный код может и не иметь такой проблемы. Зато тот, кто пользуется классом не знает ничего о вспомогательных функциях или даже какие данные этот класс содержит.
AsmGuru62 Ваш вариант без интелектуального указателя, а правила хорошего тона диктуют моду перекладывать убийство динимеческих объектов на не механизмы std::auto_ptr, std::tr1_shared_ptr, etc . То есть программист не должен задаваться вопросом "А освобождается ли у меня ресурс?". Об этом еще дядюшка Майерс неоднократно заявлял )
EvilsInterrupt Если уж решил "умничать", то признай, что твой пример тоже не удачный. auto_ptr не может корректно удалять incomplete type. shared_ptr нужен.
censored Вопрос был каков? "хочется странного", т.е. человеку нужно направление, так? А значит примера до полной компиляции можно и не давать! ну и второе!!! Походу ты адски слепой человек, твои слова: >>корректно удалять incomplete type. shared_ptr нужен. можно было и не писать, если бы ты ВНИМАТЕЛЬНО прочитал мой пост и увидел бы: А тут, есть шаред_птр!!! Разуй глаза в след. раз, когда будешь чтото критиковать! и включай голову
Топик стартеру не нужен классический pImpl, т.к. прятать нужно только методы, а не данные. Достаточно будет: Код (Text): // C.h class C { int f1(); struct Impl; public: int f2(); }; // C.cpp struct C::Impl { static int f2_hlpr(C *pThis) { return pThis->f1(); } }; int C::f2() { return Impl::f2_hlpr(this); }
>>Деструктор всегда вызовется. Не всегда. К примеру если во время работы конструктора будет сгенерировано исключение, то деструктор нихрена не вызовется!
EvilsInterrupt В конструкторе сложный код не надо писать - чтобы не было исключений. Выделить память и почистить переменные - и если это уже "падает", тогда архитектурные замыслы уже не нужны.
AsmGuru62 Исключения в С++ - это не только результат "падений", но и способ обработки логических ошибок. Фактически, синхронный выброс исключения (через throw) - это штатный способ вернуть ошибку из конструктора.