Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: C++ property  (Прочитано 17627 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Алик
Постоялец

kz
Offline 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
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #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++ » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алик
Постоялец

kz
Offline 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
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 08-07-2004 20:08 » 

Xeysan, не, тут немного другой смысл. Запись в свойство вызывает ф-ию его обслуживающую, с передачей ей записываемого значения. Зафиксируется ли это значение - не важно - это вторично. Чтение же то же вызывает ф-ию. Т.е. свойство не обязано привязываться к переменным.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алик
Постоялец

kz
Offline 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 » 

Цитата: SOS
Почему так сложно   Я шокирован! Не понял??

В C++ предусмотренны так называемые property  Отлично

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

1. Расширенный атрибут __declspec является "изобретением" Microsoft, а вовсе не частью синтаксиса C++. Поэтому данный ответ сгодился бы, будь вопрос задан в соседнем разделе, посвященном различным реализациям компиляторов C++ и соответствующим расширениям синтаксиса. Поскольку вопрос был задан по стандартному C++, рекомендовать использование property в таком виде невозможно.

2. Конструкция __declspec(property(...)) была задумана как средство для поддержки программирования объектов COM, хотя может успешно применяться и в обычных программах. Поскольку с появлением .NET необходимость в использовании COM будет постепенно уменьшаться, не исключено, что в очередной версии Visual C++ мы уже не встретим этой конструкции. Следовательно, ее применение в программах, которые планируется поддерживать еще некоторое время, нецелесообразно и даже опасно.

Так что, пожалуй, придется вместо свойств пользоваться парами методов GetProp/SetProp. Не так элегантно, конечно, но обходятся же в Java подобными средствами.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 24-08-2004 05:35 » 

comm, красиво. MFC тоже по такому же принципу написан - сидишь и ругаешься иной раз, где там под хитросплетениями define'ов зарыт реальный код, чтобы понять, отчего что-то не работает или работает не так, как надо. У Страуструпа, например, сказано, что макроопределения - зло в C++, но благо для C.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines