Алик
Постоялец
Offline
|
|
« : 08-07-2004 10:27 » |
|
Один из минусов С++ - отсутствие аналога дельфийского property. Можно, конечно, добиться того же эффекта с помощью operator=(), operator type() и т.д. Я так думал. Пока не взялся... :oops: Не могу найти элегантного решения, и все! Или неполучается вообще, или получается очень неудобно, или с абсолютно не оправданными накладными расходами. Может, кто поделится секретом мастерства... В частности, охота, чтобы было так: class A{ public: property DWORD height; DWORD setheight(DWORD n){say("setting height");return fheight=n;}; ... }
... A a; a.height=5; //при этом должно вызываться setheight(5);
fheight - неявно объявленная переменная, хранящая значение свойства. Ее значение подставляется вместо a.height в выражениях. Ее может и не быть, если чтение тоже происходит через метод. В общем, все как в старине Дельфи. Кстати, если есть fheight, то желателен прямой доступ к нему методам класса A (проперти - это ж для интерфейсных целей). Есть идеи - делитесь!
|
|
« Последнее редактирование: 29-11-2007 21:17 от Алексей1153++ »
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #1 : 08-07-2004 10:46 » |
|
Алик, ну, а почему бы тебе не вызывать этот setheight() непосредственно? Не уже ли конструкция "=5" сложнее чем "(5)" ? А чтобы неповадно было "свойства" править напрямую, делай их private или protected, а для чтения используй метод getheight(). Загляни в документацию по Qt - хороший пример. У них ни одного свойства напрямую не доступно. class aaa { private: int _prop_height; int _prop_length; public: int height(void) { return _prop_height; } int length(void) { return _prop_length; } void setHeight(int n) { .....; _prop_height=n; } void setLength(int n) { .....; _prop_length=n; } };
aaa a; int b;
a.setHeight(5); b=a.height();
|
|
« Последнее редактирование: 29-11-2007 21:18 от Алексей1153++ »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #2 : 08-07-2004 11:01 » |
|
Ну да, не слишком коряво. Можно и так. Но, на мой взгляд, читабельнее, что ли, было бы, если б так: a.Height=5; //и тут оно, такое мало того, что записало в переменную пятерку, так еще и на экране размер поменяло... Ну ладно, согласен, это уже каприз... Но иногда так хочется комфорта в нашей непростой жизни
|
|
|
Записан
|
|
|
|
Xeysan
Гость
|
|
« Ответ #3 : 08-07-2004 19:56 » |
|
Можно возвращать ссылку на обьект-член-класса ( аттрибут ), тогда получиться что-то в этом роде... #include <iostream>
class Test { int value_;
public: int& Value() { std::cout << "set" << std::endl; return value_; }
const int& Value() const { std::cout << "get" << std::endl; return value_; } };
void ShowT( const Test& t ) { std::cout << t.Value(); }
int main( void ) { Test t;
t.Value() = 2; ShowT( t ); return 0; } Хотя, да, выглядит не-фонтан. И с функцией я сжульничал
|
|
« Последнее редактирование: 29-11-2007 21:19 от Алексей1153++ »
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #4 : 08-07-2004 20:08 » |
|
Xeysan, не, тут немного другой смысл. Запись в свойство вызывает ф-ию его обслуживающую, с передачей ей записываемого значения. Зафиксируется ли это значение - не важно - это вторично. Чтение же то же вызывает ф-ию. Т.е. свойство не обязано привязываться к переменным.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #5 : 09-07-2004 03:06 » |
|
Я взял на себя смелось переделать пример поближе к реальному использованию свойств: class Test { int value_;
public: int& Value() { cout << "set" << endl; return value_; }
const int& Value() const { cout << "get" << endl; return value_; } };
int main(int argc, char* argv[]) { Test t; t.Value() = 2; cout << t.Value();
int i;
cin>>i; return 0; } Не работает правильно - и при чтении, и при записи вызывается метод для записи. Но идея ничего, довольно красиво может получиться, если в этом поразбираться
|
|
« Последнее редактирование: 29-11-2007 21:20 от Алексей1153++ »
|
Записан
|
|
|
|
Serega
Гость
|
|
« Ответ #6 : 09-07-2004 11:40 » |
|
template <class ValueType, class Holder> class Property { public: typedef void (Holder::*SetFunc)(const ValueType&); typedef ValueType& (Holder::*GetFunc)();
SetFunc set; GetFunc get; Holder* holder;
Property(Holder* h, SetFunc setFunc, GetFunc getFunc) { holder = h; set = setFunc; get = getFunc; }
void operator=(const ValueType& v) { (holder->*set)(v); cout << "setting: " << v << endl; }
operator ValueType() { ValueType& tmp = (holder->*get)(); cout << "getting: " << tmp << endl; return tmp; } };
class Test { int testValue; public: Property<int, Test> testProperty;
Test() : testProperty(this, setTest, getTest) { }
void setTest(const int& i) { testValue = i; }
int& getTest() { return testValue; } };
|
|
« Последнее редактирование: 29-11-2007 21:22 от Алексей1153++ »
|
Записан
|
|
|
|
comm
Гость
|
|
« Ответ #7 : 14-07-2004 15:32 » |
|
имхо вы тут чего то намудрили, имхо, тут все намного проще: property.hxx : #define PROP_ARG( type, val ) private: type val; #define PROP_SET( type, val, set ) public: void set( type x ){ val = x; } #define PROP_GET( type, val, get ) public: const type get() const { return( val ); }
#define PROPERTY( type, val, set, get ) \ PROP_ARG( type, val )\ PROP_SET( type, val, set )\ PROP_GET( type, val, get )
myclass.cpp: #include "property.hxx"
class MyClass { PROPERTY( int, _valueName, setValue, getValue ); } .... void testMyClass() { MyClass obj; obj.setValue( 5 ); TS_ASSERT_EQUALS( 5, obj.getValue() ); }
дешево и сердито. по идее можно поразлекаться с автосозданием имен, но заморочно это очень, так как внутри обьекта иногда нужно работать с самой переменной, а не с ее методами , а система имени знать не будет этот механизм у меня работает на ура, но для сложных типов данных нужно делать дополнитлеьные макросы PROPERTY_CSTR // ASCIIZ строка PROPERTY_STR // string PROPERTY_OBJ //для всех других объектов
минусы такого подхода в том что отладчиком макросы не развернешь но при корректной реализации это и не требуется и еще один момент (для тех кто танке) :
про присваимание значения переменной-члену класа напрямую obj.member = 5; var = obj.member;
лучше забыть как про страшный сон, и использользовать только методы set/get
|
|
« Последнее редактирование: 29-11-2007 21:23 от Алексей1153++ »
|
Записан
|
|
|
|
SOS
Гость
|
|
« Ответ #8 : 23-08-2004 20:42 » |
|
Почему так сложно ?? В C++ предусмотренны так называемые property Вот код: class MyClass { public: MyClass() { m_Number = 0; }
~MyClass(){}
public: int m_Number;
public: void PutNumber(int NUMBER){ m_Number = NUMBER;} int GetNumber(){ return m_Number * 5;}
__declspec(property(get=GetNumber, put=PutNumber)) int NUMBER;
};
int main(int argc, char* argv[]) { MyClass obj;
printf( "Before SET m_Number = %d \r\n", obj.m_Number );
obj.NUMBER = 9; printf( "After SET m_Number = %d \r\n", obj.m_Number );
printf( "After GET m_Number * 5 = %d \r\n", obj.NUMBER );
getch(); return 0; }
result:
Before SET m_Number = 0 After SET m_Number = 9 After GET m_Number * 5 = 45
|
|
« Последнее редактирование: 29-11-2007 21:25 от Алексей1153++ »
|
Записан
|
|
|
|
Alf
Гость
|
|
« Ответ #9 : 23-08-2004 21:15 » |
|
Почему так сложно ?? В C++ предусмотренны так называемые property Все это и впрямь красиво выглядит, да и в использовании очень удобно. Все бы хорошо, но: 1. Расширенный атрибут __declspec является "изобретением" Microsoft, а вовсе не частью синтаксиса C++. Поэтому данный ответ сгодился бы, будь вопрос задан в соседнем разделе, посвященном различным реализациям компиляторов C++ и соответствующим расширениям синтаксиса. Поскольку вопрос был задан по стандартному C++, рекомендовать использование property в таком виде невозможно. 2. Конструкция __declspec(property(...)) была задумана как средство для поддержки программирования объектов COM, хотя может успешно применяться и в обычных программах. Поскольку с появлением .NET необходимость в использовании COM будет постепенно уменьшаться, не исключено, что в очередной версии Visual C++ мы уже не встретим этой конструкции. Следовательно, ее применение в программах, которые планируется поддерживать еще некоторое время, нецелесообразно и даже опасно. Так что, пожалуй, придется вместо свойств пользоваться парами методов GetProp/SetProp. Не так элегантно, конечно, но обходятся же в Java подобными средствами.
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #10 : 24-08-2004 05:35 » |
|
comm, красиво. MFC тоже по такому же принципу написан - сидишь и ругаешься иной раз, где там под хитросплетениями define'ов зарыт реальный код, чтобы понять, отчего что-то не работает или работает не так, как надо. У Страуструпа, например, сказано, что макроопределения - зло в C++, но благо для C.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
|