Re[2]: Свойства в С++
От: jazzer Россия Skype: enerjazzer
Дата: 22.03.04 12:00
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Денис Майдыковский, Вы писали:


ДМ>>Статья:



ДМ>>Авторы:

ДМ>> Денис Майдыковский

ДМ>>Аннотация:

ДМ>>В этой статье автор рассматривает различные способы реализации свойств в стиле Visual Basic на C++. Некоторые способы специфичны для Visual C++, тогда как другие годятся для применения в любой программе, написанной на языке C++.

А>Не пойму смысл данной конструкции. Объясните что это

А>typedef proptype (propowner::*getter)();

читай про указатели на члены
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Свойства в С++
От: achp  
Дата: 22.03.04 12:03
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Не пойму смысл данной конструкции. Объясните что это

А>typedef proptype (propowner::*getter)();

Объявляется имя getter для типа "указатель на функцию-член класса propowner, не имеющую параметров и имеющую типом возвращаемого значения proptype."
Да здравствует ИМХО!
Re[2]: даааа...
От: PK Sly http://www.vocord.ru/
Дата: 22.03.04 12:06
Оценка:
Ей богу, не для этого тему поднимал. Простите, пожалуйста..
VAX/VMS rulez!
Re[2]: А реально кто ни будь использует ТАКИЕ свойства?
От: Аноним  
Дата: 10.07.04 01:32
Оценка:
Здравствуйте, SergeyBi, Вы писали:

SB>Использование шаблонов приводит к увеличению размеров исполняемого кода, поскольку компилятор будет генерировать отдельный класс для каждой пары "proptype" и "propowner".


Я чего-то не понимаю. Я думал, генерируются только те классы, которые надо?

Неужели если имеем например 100 классов, генерируется 10.000 классов для всех возможных пар?
Re: мысль
От: Atomic Max Россия  
Дата: 17.02.05 16:26
Оценка:
R>get- и set-методы можно сделать аргументами шаблона.
R>Тогда размер свойства уменьшится в 3раза.

Да, такая идея интересна, так как использует статическое программирование на этапе компиляции. Если методы доступа известны на этапе компиляции, то зачем это делать во время выполнения (передавать указатели при каждом конструировании). Так что, я полностью согласен с предыдущим оратором.

Но я озадачился другим. Можно ли не хранить вообще никаких дополнительных указателей? То есть может ли класс свойства самостоятельно вычислить указатель на класс-носитель свойства. Эта задача (применительно к подходу из статьи) эквивалентна задаче восстановления указателя на объемлющий объект-композит. То есть если у нас есть композит A, то его поле данных типа B может восстановить указатель на свой контейнер (при условии знания структуры А):

class A
{
public:
  class B
  {
  public:
    inline A * Container() 
    {
      // вычисляем смещение поля b_ внутри A
      B A::*pB = &A::b;
      // базируемся относительно своего this
      return (A*) ( size_t(this) - *((size_t *)&pB) );
    }
    //...
  }
  B b_;
  //...
}

A a;
cout << ( & A == A.b_.Container() );


Очевилно, что это вычисление не статическое и происходит во время выполнения программы.

У меня вопрос к аудитории:
Можно ли более элегантно решить именно такую задачу?
Re[2]: мысль
От: Alexey Chen Чили  
Дата: 17.02.05 22:06
Оценка:
Здравствуйте, Atomic Max, Вы писали:

AM> B A::*pB = &A::b;

AM> // базируемся относительно своего this
AM> return (A*) ( size_t(this) — *((size_t *)&pB) );

AM>У меня вопрос к аудитории:

AM>Можно ли более элегантно решить именно такую задачу?

Подсказка: зачем тебе указатель на реальный обьект, если с данными лежащими по этому указателю ты не работаешь?
Re[2]: мысль
От: _Winnie Россия C++.freerun
Дата: 18.02.05 04:19
Оценка: 2 (1) +1
Здравствуйте, Atomic Max, Вы писали:

AM>Но я озадачился другим. Можно ли не хранить вообще никаких дополнительных указателей?



//----------------------------------------------------------------------
//да, property без изменения бинарной раскладки класса 
//вызов через указатель на член убивает оптимизирующий компилятор.
//VS2003 распознает эти property в IntelliSense 

//сразу возникает вопрос, как разрулить это - 
//T Owner::GetX() const
//T Owner::GetX() const volatile
//T Owner::GetX() volatile
//Owner::x
//T Owner::GetX() 
//T &Owner::GetX() 
//мне кажется, что это можно сделать через 
//sizeof(overloaded_function(MakeT())) трюк, но мне лень это проверять

//тут еще подводные камни с константностью функции NAME(), 
//без парочки const_cast видимо не обойдется, если доводить до ума.

template <
  class Owner, 
  class PropT, 
  void (Owner::*Setter)(PropT), 
  PropT (Owner::*Getter)()>
struct Property
{
  Owner &owner;
  Property(Owner &owner): owner(owner) {};
  //да, void. Не хочу мозг парить.
  void operator =(const PropT &x) { (owner .* Setter)(x); }
  operator const PropT () { return (owner .* Getter)(); }
};

//можно сделать PROPERTY_RW, PROPERTY_R, PROPERTY_W, 

#define PROPERTY(NAME, Owner, T, Setter, Getter)\
Property<Owner, T, &Owner::Setter, &Owner::Getter> NAME() \
{ \
  return Property<Owner, T, &Owner::Setter, &Owner::Getter>(*this);\
}

//----------------------------------------------------------------------


#include <fstream>
#include <iostream>
#include <string>

struct MegaClass
{
private:
  int GetFromFile()
  {
    int i;
    std::ifstream f("config.txt");
    f >> i;
    return i*2;
  }

  void SetValueInFile(int i)
  {
    std::ofstream f("config.txt");
    f << i;
  }

  std::string GetS() { return "hello"; }
  void SetS(std::string sss) { std::cout <<sss; }

public:


  PROPERTY(X, MegaClass, int, SetValueInFile, GetFromFile);
  PROPERTY(Y, MegaClass, int, SetValueInFile, GetFromFile);
  PROPERTY(Sss, MegaClass, std::string, SetS, GetS);


  MegaClass()
  {
    this->X() = 0;
  }
  
};


volatile int i;


class Test2
{
private:
  void SetI(int i) { ::i = i; } 
  int GetI() { return ::i; }
public:
  PROPERTY(I, Test2, int, SetI, GetI);
};


int main()
{
  std::cout <<sizeof(MegaClass) <<"\n"; //empty class

  MegaClass mc;
  mc.X() = 10;
  int i = mc.Y();

  std::string s = mc.Sss();
  mc.Sss() = "world";

  //проверяю в листинге на asm, что компилятор уничтожает лишние вызовы.
  Test2 t;
  t.I() = 10;
  i = t.I();

  std::cout <<i;
}
Правильно работающая программа — просто частный случай Undefined Behavior
Re[3]: мысль
От: Atomic Max Россия  
Дата: 18.02.05 14:45
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

AC>Подсказка: зачем тебе указатель на реальный обьект, если с данными лежащими по этому указателю ты не работаешь?


Видимо, я не понял подсказку. Поясните, пожалуйста.

Да, я не обращаюсь к полям данных на прямую, но я должен вызывать методы объемлющего объекта (реализация "свойства" в контексте обсуждаемой статьи). А по моим сведениям, я не могу вызвать нестатический метод объекта, не имея в распоряжении указателя на сам объект.
Re[3]: мысль
От: Atomic Max Россия  
Дата: 18.02.05 15:54
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>

_W>int main()
_W>{
_W>  std::cout <<sizeof(MegaClass) <<"\n"; //empty class

_W>  MegaClass mc;
_W>  mc.X() = 10;
_W>  int i = mc.Y();

_W>  std::string s = mc.Sss();
_W>  mc.Sss() = "world";

_W>  //проверяю в листинге на asm, что компилятор уничтожает лишние вызовы.
_W>  Test2 t;
_W>  t.I() = 10;
_W>  i = t.I();

_W>  std::cout <<i;
_W>}

_W>


Да, идея интересная. Только "свойство" превратилось из поля класса в метод, поэтому надо писать пустые скобки. Интересно, что раньше, реализуя "свойство" через поле данных, я перегружал оператор () так, чтобы он возвращал результат Get-метода. Таким образом у меня появлялась возможность вызывать константные методы оригинального поля данных объекта. Например:
  //...
  const PropT operator () () { return (owner .* Getter)(); }
  //...

Теперь же придётся писать два раза скобки, чтобы спросить у строки длину :
//...
  cout << "Length is " << ms.Sss()().length() << endl;
//...
Re[4]: мысль
От: Alexey Chen Чили  
Дата: 18.02.05 18:27
Оценка: 1 (1)
Здравствуйте, Atomic Max, Вы писали:

AC>>Подсказка: зачем тебе указатель на реальный обьект, если с данными лежащими по этому указателю ты не работаешь?

AM>Видимо, я не понял подсказку. Поясните, пожалуйста.

Вот пример. Хоть он и не так изыскан как решения на шаблонах

#include <stdio.h>

#define PROPERTY(T,__type,__set,__get,__name) \
  \
  __type value() const { return resolve_(this,1)->__get(); } \
  \
  __type operator+() const { return value(); } \
  \
  operator __type () const { return value(); } \
  \
  void \
    operator = (__type const& a) { resolve_(this,1)->__set(a); } \
  \
  template <class fake> static T* resolve_(const void* p,fake) {\
    T* _ = 0; \
    return (T*)( (char*)p - ( (char*)(&_->__name) - (char*)(_) ) );\
  } 


struct Obj1 
{
  void SetP1(int a) { printf("SetP1(%d)\n",a); }
  int  GetP1() const { printf("GetP1()\n"); return 0; }
  void SetP2(int a) { printf("SetP2(%d)\n",a); }
  int  GetP2() const { printf("GetP2()\n"); return 0; }
  //union { ещё одна причина не любить gcc, 
    struct __Property_a { PROPERTY(Obj1,int,SetP1,GetP1,a) } a;
    struct __Property_b { PROPERTY(Obj1,int,SetP2,GetP2,b) } b;
  //};
};

int main ()
{
  Obj1 o;
  printf("sizeof(Obj1) = %d\n",sizeof(Obj1));
  o.a = 1;
  printf("o.a + 1 = %d\n", o.a + 1);
  o.b = 0;
  printf("o.b + 1 = %d\n", o.b + 1);
  return 0;
}
Re[3]: А реально кто ни будь использует ТАКИЕ свойства?
От: remark Россия http://www.1024cores.net/
Дата: 03.09.06 08:16
Оценка:
Здравствуйте, Awaken, Вы писали:


SB>>достоинства иногда побеждают? И какие достоинства вообще существуют кроме наглядности?


A>бывает нужно разделить операцию присваивания для левого и правого оператора на 2 разных

A>метода.


Левый и правый оператор присваивания???



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: А реально кто ни будь использует ТАКИЕ свойства?
От: Roman Odaisky Украина  
Дата: 03.09.06 11:15
Оценка: :)
Здравствуйте, remark, Вы писали:

R>Левый и правый оператор присваивания???


http://rsdn.ru/Forum/?mid=577485
Автор: PK Sly
Дата: 22.03.04


а ты для чего?
До последнего не верил в пирамиду Лебедева.
Re[5]: А реально кто ни будь использует ТАКИЕ свойства?
От: remark Россия http://www.1024cores.net/
Дата: 03.09.06 20:08
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Здравствуйте, remark, Вы писали:


R>>Левый и правый оператор присваивания???


RO>http://rsdn.ru/Forum/?mid=577485
Автор: PK Sly
Дата: 22.03.04


RO>а ты для чего?


здесь
Автор: Doc
Дата: 03.09.06


Получается, что для этого же


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: мысль
От: alno http://blog.alno.name/
Дата: 26.05.08 15:56
Оценка: 2 (1) -1
здесь аналогичное решение, только на смеси макросов и шаблонов.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.