Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Delphi "class helper for ...", аналог для C++ Builder 
V
    Опции темы
Doga
Дата 2.7.2015, 14:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



Всем привет.

Кто-нибудь знает конструкцию для С++ Builder , аналогичную нижеследующему выражению в Delphi?

Например:
Код

TCustomFormHelper = class helper for TCustomForm
    function DefaultClientProc: TFarProc;
end;


Данная конструкция, а именно "class helper for ", позволяет получить доступ к приватным членам класса в Delphi.
Существует ли что-либо подобное для С++ Builder?

Это сообщение отредактировал(а) Doga - 2.7.2015, 14:25
PM MAIL WWW   Вверх
rudolfninja
Дата 2.7.2015, 15:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 341
Регистрация: 19.2.2013
Где: г. Минск

Репутация: нет
Всего: 6



Привет.
Есть два способа:
1) Дружественные функции и классы.
2) Унаследоваться от нужного тебе класса и использовать свой класс.
PM MAIL Skype   Вверх
Alexeis
Дата 2.7.2015, 16:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 26
Всего: 459



Цитата(rudolfninja @  2.7.2015,  16:33 Найти цитируемый пост)
Привет.
Есть два способа:
1) Дружественные функции и классы.
2) Унаследоваться от нужного тебе класса и использовать свой класс. 

  На самом деле нет ни одного аналогичного способа. Класс хелпер используется случае когда мы не имеем доступа к реализации или не хотим вмешиваться в работу класса написанного сторонним разработчиком. Класс хелпер не меняет ни длину объекта, ни таблицу VMT, ни RTTI. Просто возможность создать функции типа геттера или сттера не предусмотренные разработчиком. 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Doga
Дата 2.7.2015, 16:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



  Насколько мне известно, функцию (или класс) можно сделать дружественной какому-либо классу только при объявлении самого класса. 
TCustomForm, к сожалению, уже объявлен.

  А наследники класса по определению не могут получить доступ к членам класса родителя, если те объявлены в секции private.
Для того она и существует.

  Так что, оба этих способа не годятся.


PM MAIL WWW   Вверх
rudolfninja
Дата 2.7.2015, 17:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 341
Регистрация: 19.2.2013
Где: г. Минск

Репутация: нет
Всего: 6



Цитата(Doga @  2.7.2015,  16:52 Найти цитируемый пост)
  А наследники класса по определению не могут получить доступ к членам класса родителя, если те объявлены в секции private.
Для того она и существует.

Да, что то я подумал, что они protected, не обратил внимание на слово "приватным".
По поводу дружественного класса, я полагаю, у тебя ведь есть доступ к исходныму коду класса TCustomForm? Так почему бы не добавить туда класса друга или не переместить нужные методы в protected секцию? Нарушается инкапсуляция, но это не самое страшное. 
В прицнипе, получается, что мы вмешиваемся в работу класса, написанного сторонними разработчиками. Так, что, выходит, что Alexeis прав, аналогов нет.

Это сообщение отредактировал(а) rudolfninja - 2.7.2015, 17:02
PM MAIL Skype   Вверх
Doga
Дата 2.7.2015, 17:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



2rudolfninja
Эй! TCustomForm прямой родитель класса TForm ! 
Эти классы написаны не какими то  сторонними разработчиками, а самим СОЗДАТЕЛЕМ! smile 

2Alexeis
Похоже, я не корректно сформулировал вопрос.
Мне как раз и нужен класс хелпер, только для С++ Builder smile
Если б я знал, как его использовать... 

Это сообщение отредактировал(а) Doga - 2.7.2015, 17:09
PM MAIL WWW   Вверх
rudolfninja
Дата 2.7.2015, 17:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 341
Регистрация: 19.2.2013
Где: г. Минск

Репутация: нет
Всего: 6



Вот нашел интересный способ получения доступа к приватным членам класса, я про такой не знал.
Но в твоем случае, это будет трудно.
PM MAIL Skype   Вверх
Doga
Дата 2.7.2015, 17:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



Фу - фу - фу! И зачем такое предлагать?
PM MAIL WWW   Вверх
rudolfninja
Дата 2.7.2015, 17:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 341
Регистрация: 19.2.2013
Где: г. Минск

Репутация: нет
Всего: 6



Как один из вариантов решения проблемы.
PM MAIL Skype   Вверх
Guinness
Дата 3.7.2015, 07:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 310
Регистрация: 21.6.2009
Где: Зеленоград

Репутация: нет
Всего: 10



Цитата(Doga @  2.7.2015,  18:29 Найти цитируемый пост)
Фу - фу - фу! И зачем такое предлагать? 

Нормальный вариант решения данной "проблемы". Правда, было бы лучше, если бы была указана причина, по которой необходимо получить доступ к приватным членам класса. Возможно, тут просто какие-то проблемы с пониманием работы класса, либо проблемы с архитектурой приложения, либо тот самый редкий случай, когда без этого не обойтись. Но тогда придётся пользоваться всякими низкоуровневыми возможностями языка.
PM MAIL   Вверх
Alexeis
Дата 3.7.2015, 14:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 26
Всего: 459



Цитата(Doga @  2.7.2015,  18:01 Найти цитируемый пост)
Похоже, я не корректно сформулировал вопрос.
Мне как раз и нужен класс хелпер, только для С++ Builder 
Если б я знал, как его использовать... 

  Можно кусочек кода написать на делфи, и включить в проект на С++ Builder. Проект С++ Builder допускает и паскалевские файлы.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Doga
Дата 3.7.2015, 16:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



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

Однако. 

В общем случае, класс может содержать множество (в том числе и однотипных) элементов, и далеко не факт, что необходимый будет объявлен первым. 
Ладно, пока это не проблема - идём дальше. Пусть нужный нам класс является наследником другого класса, который также является наследником уже своего родителя, и т.д.. 
В итоге, наш класс может быть наследником длинной цепочки предков, каждый из которых, в свою очередь, может обладать нетривиальной структурой.
Какой адрес, с каким смещением, какое выравнивание надо будет использовать для получения доступа к нужному элементу, применяя предложенный способ? 
Даже если получить доступ к этому элементу удастся (предположим, удалось одурачить компилятор и вычислить? (подобрать!) смещение), 
можно ли будет перенести такой код в другую версию компилятора (IDE) без изменений? Или опять танцы с бубном? 

Короче, этот способ не переносим и не безопасен. Я бы согласился на такое только от безысходности, и то не факт...

Теперь расскажу что мне было нужно. 
Нужно чтобы клиентское окно MDI приложения не рисовало вогнутую (lowered) рамку, когда в нем не открыто ни одно дочернее окно или когда их свойство WindowStete != wsMaximized.
Судя по исходникам Forms.pas, необходимо перехватить обработку системного сообщения 0x3F (я не знаю, что это такое). В этом месте можно отключить отрисовку этой рамки.
Но, чтобы всё было корректно, перед отключением рамки не плохо было бы вызвать штатную оконную процедуру(хотя и без неё вроде как работает). 
Так вот, в классе TCustomForm есть приватный член - void * FDefClientProc, являющийся указателем на ту самую оконную процедуру Клиентского окна главной формы MDI приложения.

Рассмотрим теперь иерархию классов:
TObject->TPersistent->TComponent->TControl->TWinControl->TScrollingWinControl->TCustomForm->TForm->TMyMDIForm. 

Таким образом, имеется экземпляр класса, 9-ый в цепочке наследников (TMyMDIForm), при этом нужно получить доступ к  приватному элементу 7-го наследника(TCustomForm).
Таким способом - не реально.

В результате, написал класс-хелпер на паскале и подключил к проекту. Всё работает. 

Не понятно только, почему в Дельфи  класс-хелпер есть, а в Билдере его нет?

Это сообщение отредактировал(а) Doga - 3.7.2015, 16:30
PM MAIL WWW   Вверх
Doga
Дата 6.7.2015, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



Модуль FormHelper.pas
Код

unit FormHelper;

interface

uses Forms, Windows;

function DefaultClientProc(ACustomForm: TCustomForm): TFarProc;

type
  TFormHelper = class helper for TCustomForm
    function DefClientProc: TFarProc;
  end;

implementation

function TFormHelper.DefClientProc: TFarProc;
begin
  Result := Self.FDefClientProc;
end;

function DefaultClientProc(ACustomForm: TCustomForm): TFarProc;
begin
  if ACustomForm <> Nil then
  begin
    Result := ACustomForm.DefClientProc;
  end
  else
    Result := Nil;
end;

end.


FormHelper.hpp (хидер) для FormHelper.pas, генерируется автоматически:
Код

#ifndef FormhelperHPP
#define FormhelperHPP

#pragma delphiheader begin
#pragma option push
#pragma option -w-      // All warnings off
#pragma option -Vx      // Zero-length empty class member functions
#pragma pack(push,8)
#include <System.hpp>   // Pascal unit
#include <SysInit.hpp>  // Pascal unit
#include <Forms.hpp>    // Pascal unit
#include <Windows.hpp>  // Pascal unit

//-- user supplied -----------------------------------------------------------

namespace Formhelper
{
//-- type declarations -------------------------------------------------------
typedef void *TFormHelper;

//-- var, const, procedure ---------------------------------------------------
extern PACKAGE void * __fastcall DefaultClientProc(Forms::TCustomForm* ACustomForm);

} /* namespace Formhelper */
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE)
using namespace Formhelper;
#endif
#pragma pack(pop)
#pragma option pop

#pragma delphiheader end.
//-- end unit ----------------------------------------------------------------
#endif    // FormhelperHPP


Использование:
Код

WNDPROC DefProc  = (WNDPROC)DefaultClientProc((TCustomForm *)this);


Перегруженный ClientWndProc:
Код

void __fastcall TMyMDIForm::ClientWndProc(Messages::TMessage &Message)
{
  if (Message.Msg == 0x3F) 
  {
    //!!!
    Message.Result = CallWindowProc((WNDPROC)DefaultClientProc((TCustomForm *)this), ClientHandle, Message.Msg, Message.WParam, Message.LParam);
    
    DWORD ExStyle;

    ExStyle = GetWindowLongPtr(ClientHandle, GWL_EXSTYLE);
    ExStyle = ExStyle & (~WS_EX_CLIENTEDGE);
    SetWindowLongPtr(ClientHandle, GWL_EXSTYLE, ExStyle);
    SetWindowPos(ClientHandle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED + SWP_NOACTIVATE + SWP_NOMOVE + SWP_NOSIZE + SWP_NOZORDER);
  } 
  else 
  {
    TForm::ClientWndProc(Message);
  }
}


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



Это сообщение отредактировал(а) Doga - 6.7.2015, 11:49
PM MAIL WWW   Вверх
Alexeis
Дата 6.7.2015, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 26
Всего: 459



Цитата(Doga @  3.7.2015,  17:01 Найти цитируемый пост)
Не понятно только, почему в Дельфи  класс-хелпер есть, а в Билдере его нет?

  Побуду немного в роли КЭПа. Наверное потому что это разные языки.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Doga
Дата 6.7.2015, 15:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



Это для меня не новость, однако, компилятор у них один - это то, как раз, на мысль и наводит...

С точки зрения программиста на С++, чувствуешь себя немного обделённым, по сравнению с пользователями Дельфи :( 

Это сообщение отредактировал(а) Doga - 6.7.2015, 15:37
PM MAIL WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0612 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.