Консультация № 170046
30.06.2009, 23:39
0.00 руб.
0 23 1
Здравствуйте эксперты, продолжаю дальше изучать С++ Builder пока что. Такой вопросик. Как получить указатель на какое то конкретное свойство объекта, а не на объект целиком. И почему если просто объявляешь указатель на обычную переменную(Int например) то при взятии ее адреса надо писать &, а когда адрес объекта присваю не надо?В приложении провел код нажатия клавиши мыши. Как мне мне получить указатель не на весь Edit, а только на св-во Caption.
Пытался писать что то типа TCaption *C; вроде компилятор не ругался, но я правда не уверен есть ли вообще такой класс или тип и т.д. А попытки толкого записать адресс и изменить через указатель адрес успехом не увенчались. Как это сделать?

Приложение:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int a=6;
Edit1->Text=a;
int *b;
b=&a;
*b=15;
Edit2->Text=a;
TEdit *E;
E=Edit1;
E->Text=102;


}

Обсуждение

Неизвестный
01.07.2009, 00:08
общий
это ответ
Здравствуйте, Tribak.
Как получить указатель на какое то конкретное свойство объекта, а не на объект целиком.

Код:

class A
{
public:
int b;
}

...

A a;
int* iptr=&a.b;


И почему если просто объявляешь указатель на обычную переменную(Int например) то при взятии ее адреса надо писать &, а когда адрес объекта присваю не надо?

Не совсем понятно, что Вы имеете ввиду, но, как видите по предыдущему примеру, надо и для класса &.

Как мне мне получить указатель не на весь Edit, а только на св-во Caption.

А разве у TEdit есть public свойство Caption? Оно protected, а значит Вы можете получить доступ к нему только из наследника класса.

Пытался писать что то типа TCaption *C; вроде компилятор не ругался, но я правда не уверен есть ли вообще такой класс или тип и т.д.

Такой класс есть.
5
Неизвестный
01.07.2009, 09:11
общий
Так я на класс когда TEdit просто присал E=Edit ( в приложении), а почему если оно protected то можно самому спокойно менять его содержимое, а не через методы класса?
Неизвестный
01.07.2009, 10:17
общий
Tribak:
Так я на класс когда TEdit просто присал E=Edit ( в приложении)

Дело в том, что Edit1, у Вас в примере, это не TEdit, а TEdit*. Т.е. это уже указатель. Поэтому применять операцию взятия адреса к нему не нужно.

а почему если оно protected то можно самому спокойно менять его содержимое, а не через методы класса?

Т.е. вы хотите сказать, что можете прямо написать Edit1->Caption="Строка";??? Я вот не могу.
Воспользуйтесь контекстной справкой. Наведите курсор на Edit1 и нажмите F1. Выберите TEdit Members и посмотрите сами.

Неизвестный
01.07.2009, 10:33
общий
ну у Edit1 помойму свойства Caption, есть Text
Неизвестный
01.07.2009, 10:36
общий
а вот у Label есть Caption
пытаюсь сделать вот так:
///1111
Label1->Caption="строка";
////2222
TCaption *L;
L=&(Label1->Caption);
L="СТРОКА";
1ое работает, а второе не работает
Неизвестный
01.07.2009, 10:44
общий
Tribak:
Нет. Есть и Text и Caption. Только Caption protected, как видно из рисунка, а Text __published. Вы справку смотрели? Поищите. Там самому можно найти ответы на большинство вопросов.
Неизвестный
01.07.2009, 11:19
общий
Tribak:
Обратите внимание как декларирован класс TLabel:
Код:

class DELPHICLASS TLabel;
class PASCALIMPLEMENTATION TLabel : public TCustomLabel
{
typedef TCustomLabel inherited;

__published:
__property Align = {default=0};
__property Alignment = {default=0};
__property Anchors = {default=3};
__property AutoSize = {default=1};
__property BiDiMode;
__property Caption;
__property Color;
__property Constraints;
__property DragCursor = {default=-12};
__property DragKind = {default=0};
__property DragMode = {default=0};
__property EllipsisPosition = {default=0};
__property Enabled = {default=1};
__property FocusControl;
__property Font;
__property GlowSize = {default=0};
__property ParentBiDiMode = {default=1};
__property ParentColor = {default=1};
__property ParentFont = {default=1};
__property ParentShowHint = {default=1};
__property PopupMenu;
__property ShowAccelChar = {default=1};
__property ShowHint;
__property Transparent;
__property Layout = {default=0};
__property Visible = {default=1};
__property WordWrap = {default=0};
__property OnClick;
__property OnContextPopup;
__property OnDblClick;
__property OnDragDrop;
__property OnDragOver;
__property OnEndDock;
__property OnEndDrag;
__property OnMouseActivate;
__property OnMouseDown;
__property OnMouseMove;
__property OnMouseUp;
__property OnMouseEnter;
__property OnMouseLeave;
__property OnStartDock;
__property OnStartDrag;
public:
/* TCustomLabel.Create */ inline __fastcall virtual TLabel(Classes::TComponent* AOwner) : TCustomLabel(AOwner) { }

public:
/* TGraphicControl.Destroy */ inline __fastcall virtual ~TLabel(void) { }

};

И свойство Caption:
Код:

__property Caption;

__property это расширение языка придуманное Borland для поддержки vcl.
Свойства декларируются типа так:
Код:

class myclass
{
private:
int somenumber;
protected:
int __fastcall GetSomeNumber()
{
return somenumber;
}
void __fastcall SetSomeNumber(int val)
{
somenumber=val;
}
public:
__property int SomeNumber=
{
read=GetSomeNumber,
write=SetSomeNumber
}
}


Т.е. доступ к переменной-члену класса осуществляется через методы, хотя Вы и пишете SomeNumber=2 и т.п.
Это сделано для того, чтоб Вы не могли получить доступ к полю напрямую, а только через методы класса и при этом, чтоб форма записи была более привычна, чем писать SetSomeNumber(2) и т.п.

Вы не можете изменить это свойство таким образом. Да в этом и нет нужды.
Неизвестный
01.07.2009, 11:25
общий
Я пока не силен в том что написано, но я так понял что это называется перегрузкой оператора равно?
А можно к каким-то отдельным полям получить доступ через указатель? У любого компонента.
Неизвестный
01.07.2009, 12:08
общий
Tribak:
К полям можно если они общедоступны. Но такого в нормально спроектированных классах не встречается. Можете сами свой класс спроектировать и потренироваться на нем, если так хочется через указатели.

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

Да и нужды в этом нет. Поверьте.

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

То, что хотите Вы лишило бы Вас этих возможностей и породило бы небезопасный код.
Неизвестный
01.07.2009, 12:15
общий
Tribak:
Цитата: 29204
Я пока не силен в том что написано, но я так понял что это называется перегрузкой оператора равно?

Это не так. Вам не мешало бы углубиться в теорию объектно ориентированного программирования на C++. Или же параллельно изучать C#. Там свойства являются частью стандарта(в отличие от C++) и это могло бы помочь разобраться. А может и понравиться и тогда забросите это чудо C++ Builder.
Неизвестный
01.07.2009, 12:26
общий
да я пока просто C++ изучаю, раньше Pascal и Delphi писал, сейчас вот C++ показали, так мне синтаксис языка понравился, помойму он гораздо мощнее и удобней. Теперь осваиваюсь, что да как, потом еще не знаю на чем буду работать и с чем, а пока вот знакомлюсь. Кроме C++ Builder ничего не знаю чтобы под Windows не консольные приложения писать(консольные на CodeBlocks писал, сейчас дальше хочу идти), так с ним и работаю. Освоюсь с C++ так и до C# доберу и всего остального, а пока азы постигаю.
Неизвестный
01.07.2009, 12:30
общий
а можно вообще как то до какого-нить свойства добраться через отдельную переменную или только через #define делать замену?
Просто скажем вначале программы хочу тоже Caption вначале у одно Label менять, а потом у другой, так бы присвоить адрес Caption другого Label и менять через туже переменную значения св-ва. Можно что=то в таком духе делать?
Неизвестный
01.07.2009, 12:32
общий
Tribak:
C++ показали, так мне синтаксис языка понравился, помойму он гораздо мощнее и удобней

Да.

ничего не знаю чтобы под Windows не консольные приложения писать

Лучше Microsoft Visual Studio и C# ничего нет. ИМХО.
Неизвестный
01.07.2009, 12:49
общий
ну я сейчас уже кучу книг взял по C++ builder как уже тут на портале посоветовали, автора Архангельского. Потом думаю до всего этого доберусь.
Неизвестный
01.07.2009, 13:05
общий
Tribak:
а можно вообще как то до какого-нить свойства добраться через отдельную переменную или только через #define делать замену?

Насчет #define я не понял.

Просто скажем вначале программы хочу тоже Caption вначале у одно Label менять, а потом у другой, так бы присвоить адрес Caption другого Label и менять через туже переменную значения св-ва. Можно что=то в таком духе делать?

Суть в том, что Вы не можете получить адрес Caption в принципе. Если Вы напишите &Label1->Caption компилятор выдаст ошибку E2027 Must take address of a memory location. И будет прав. Если Вы внимательно читали пост, где я показывал, что такое свойства то Вы поймете, что свойство действительно не имеет адреса в памяти, а c полем класса(а может быть и не одним) работают методы свойства(read/write).

Но можно создать список/массив/словарь и т.п. указателей на требуемые контролы. Например TLabel* и потом обращаться используя итератор/индекс/ключ, например. Либо же использовать свойство Components формы.

Код:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
for(int i=0;i<ComponentCount;++i)
{
TComponent* component=Components[i]; // Берем следующий компонент
TLabel* label=dynamic_cast<TLabel*>(component); // Пытаемся привести его к TLabel*
if(label)
{
// Если успешно - меняем Caption
label->Caption="Это мой новый Caption";
}
}
}
Неизвестный
01.07.2009, 13:23
общий
а тоесть нельзя просто найти как-то адрес на диск или в оперативной памяти где находится байты отвечающие за свойство и записать туда что-нить свое? Или компилятор не даст это сделать если я даже какой-то переменной исхитрюсь дать адрес где находится физически свойство?
а на счет #define то можно просто написать
....
#define AA Label1->Caption
....
AA="String"; и все работает, все символы AA перед компиляцией заменяются на Label1->Caption
Неизвестный
01.07.2009, 13:30
общий
Tribak:
#define AA Label1->Caption
....
AA="String"; и все работает, все символы AA перед компиляцией заменяются на Label1->Caption

Смысла в этом ноль. Чем не устраивает просто Label1->Caption="String" ?
Не стоит, по возможности, использовать директиву #define вообще, программируя на C++. Исключение составляет использование для предотвращения повторного включения заголовков. Вы, наверное, видели подобное:
Код:

#ifndef Unit1H
#define Unit1H
...
#endif

Все, что может #define, и даже больше в C++ можно реализовать при помощи констант и шаблонов.

а тоесть нельзя просто найти как-то адрес на диск или в оперативной памяти где находится байты отвечающие за свойство и записать туда что-нить свое?

Компилятору все равно куда Вы будете писать. Если найдете. Только как Вы это себе представляете? Тоже смысла в этом нет. Гораздо удобнее пользоваться теми способами, о которых я писал постом выше.
Неизвестный
01.07.2009, 13:42
общий
ну моя запись короче, если постоянно надо менять с свойстве Label1->Caption то гораздо проще писать AA="...." чем всю эту строку.
А адрес охото знать чтобы самому иметь ко всему доступ вручную, так мне кажется свободы как то больше чувствуешь. Возможно ведь наверняка такая ситуация когда Label1 не обьявлено а поменять его значения надо, я пока до такого не добирался правда, но допустим открыта одна форма, а надо поменять свойство объекта находящегося на другой форме, если до этого получить адрес этого свойства и записать в файл адрес а с другой формы его считать и писать с другой формы туда все что хочешь. Хочется не методами и свойствами все менять, а по адресу просто переписать как надо и чтобы все тип-топ, а не заботится о том что где объявлено.
Неизвестный
01.07.2009, 14:01
общий
Tribak:
Цитата: 29204
ну моя запись короче, если постоянно надо менять с свойстве Label1->Caption то гораздо проще писать AA="...." чем всю эту строку.

Короче - да, а понятнее ли? Да и стиль программирования неважный будет если так делать. Тем более, что большую часть этой строки пишет IntelliSence.

Перечитайте прошлый пост про #define

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

Знание адреса ничего не дает в этих задачах в принципе. Только увеличивает вероятность ошибок.

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

Ну это вообще. В файл ничего писать не надо. Каждая форма должна заниматься своими делами. И хотя Вы можете открыть доступ к контролам формы для других, не стоит этого делать. Лучше создать общедоступный метод для требуемой работы. Но гораздо лучше применить модель основанную на событиях для взаимодействия между формами.

Хочется не методами и свойствами все менять, а по адресу просто переписать как надо и чтобы все тип-топ, а не заботится о том что где объявлено.

Вот как раз так все тип-топ и не получится. Все будет наоборот.
Неизвестный
02.07.2009, 01:34
общий
Инкапсуляцию, конечно, нарушать нельзя. Она как раз и придумана, чтобы уменьшить связанность объектов.

Если нужно унифицировать доступ к свойству класса, можно использовать указатели на функции-члены класса.

Пример:
Код:
class something
{
public:
void some_proc(int)
{
}

public:
float some_const_proc() const
{
return 0.f;
}
};

int main()
{
// объявление указателя на функцию-член класса
void (something::*proc_ptr)(int);
// взятие адреса
proc_ptr = &something::some_proc;

// объявление указателя на константную функцию
float (something::*const_proc_ptr)() const;
// взятие адреса
const_proc_ptr = &something::some_const_proc;

// вызов
something s;
(s.*proc_ptr)(42);

// косвенный вызов (через указатель на объект)
something* s_ptr = &s;
float result = (s_ptr->*const_proc_ptr)();
}
Неизвестный
02.07.2009, 01:47
общий
Ross:
Дело в том, что в C++ Builder свойства класса это несколько иное. Речь шла не об этом.
Неизвестный
02.07.2009, 02:14
общий
Micren:
Из вашего поста я понял, что property в C++ Builder преобразуются в пару геттер-сеттер. Значит можно к ним обращаться, используя указатель на функцию. Или я не прав?
Неизвестный
02.07.2009, 02:31
общий
Ross:
Ну и на какую из этих двух функций будет указатель? Сами то функции protected.

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

У меня не получилось. Причем компилятор даже не выдает никаких предупреждений. Типа все правильно. Но результат нулевой.
Форма ответа