PImpl и сравнение: возможно ли без RTTI ?
От: Аноним  
Дата: 28.07.09 12:08
Оценка:
Пусть есть базовый класс реализации

class Impl_base;


и класс-указатель на реализацию

class PImpl {
 public:
  bool operator == (const PImpl &impl) const;

 private:
  Impl_base *m_pImpl;
};


Вопрос, как мне реализовать operator ==() ?

Напрашивается такое решение: в базовом классе определяем чисто виртуальную функцию IsEqual() и дергаем ее в теле PImpl::operator ==().

class Impl_base {
 public:
  virtual bool IsEqual(const Impl_base* pImpl) const=0;
};

bool PImpl::operator == (const PImpl &impl) const
{
  return m_pImpl->IsEqual(impl);
}


И делаем конкретные реализации Impl_base, в которых определяем функцию IsEqual().

class Impl_A: public Impl_base {
 public:
  virtual bool IsEqual(const Impl_base* pImpl) const;
  {
    const Impl_A *pImplA=dynamic_cast<const Impl_A*>(pImpl);
    if (!pImplA) return false;
    return m_a==pImplA->m_a;
  }

 private:
  int m_a;
};



Смущает то, что, для решения такой, казалось бы простой задачи приходится использовать тяжелую артиллерию — RTTI.
Можно ли как-то сравнить PImpl-ы, не использую dynamic_cast<>(), typeid(), и уж тем более самопальные заменители RTTI ?
Re: PImpl и сравнение: возможно ли без RTTI ?
От: Sashaka Россия  
Дата: 28.07.09 12:41
Оценка:
Здравствуйте, Аноним, Вы писали:

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

А>Можно ли как-то сравнить PImpl-ы, не использую dynamic_cast<>(), typeid(), и уж тем более самопальные заменители RTTI ?

class Impl_A: public Impl_base {
 public:
  virtual bool IsEqual(const Impl_base* pImpl) const;
  {
    return m_a==pImplA->GetA();
  }
  protected:
  virtual int GetA() const
  {
     return m_a;
  }
 private:
  int m_a;
};
Re: PImpl и сравнение: возможно ли без RTTI ?
От: Caracrist https://1pwd.org/
Дата: 28.07.09 13:50
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Пусть есть базовый класс реализации


А>
А>class Impl_base;


А> и класс-указатель на реализацию


А>
А>class PImpl {
А> public:
А>  bool operator == (const PImpl &impl) const;

А> private:
А>  Impl_base *m_pImpl;
А>};


А>Вопрос, как мне реализовать operator ==() ?



bool PImpl::operator == (const PImpl &impl) const
{
  return *m_pImpl == *(impl.m_pImpl);
}

~~~~~
~lol~~
~~~ Single Password Solution
Re: PImpl и сравнение: возможно ли без RTTI ?
От: Vain Россия google.ru
Дата: 28.07.09 13:57
Оценка: 23 (3)
Здравствуйте, Аноним, Вы писали:

А>Пусть есть базовый класс реализации

A>...
А>Смущает то, что, для решения такой, казалось бы простой задачи приходится использовать тяжелую артиллерию — RTTI.
А>Можно ли как-то сравнить PImpl-ы, не использую dynamic_cast<>(), typeid(), и уж тем более самопальные заменители RTTI ?
class Impl_A: public Impl_base {
public:
  virtual bool IsEqual(const Impl_base* pImpl) const;
  {
    return GetClassId() == pImplA->GetClassId();
  }
 
  virtual void* GetClassId() const
  {
     static int uniqAddressVar = 0;
     return &uniqAddressVar;
  }
};

Работает если Flat memory.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re: PImpl и сравнение: возможно ли без RTTI ?
От: superman  
Дата: 28.07.09 14:30
Оценка: 2 (1) :)
Здравствуйте, Аноним, Вы писали:
А>Можно ли как-то сравнить PImpl-ы, не использую dynamic_cast<>(), typeid(), и уж тем более самопальные заменители RTTI ?

как насчет двойной диспечеризации?

class Impl_A;
class Impl_base {
public:
    virtual bool IsEqual(const Impl_base& other) const=0;
    virtual bool IsEqual(const Impl_A& other) const=0;
};

class Impl_A: public Impl_base {
public:
    virtual bool IsEqual(const Impl_base& other ) const;
    {
        return other.IsEqual(*this);
    }
     virtual bool IsEqual(const Impl_A& other) const=0
     {
        // compare somehow 2 Impl_A
     }
};


Да, а вообще накой вам эта иерархия пиплов? ИМХО слишком сложно.
Re: PImpl и сравнение: возможно ли без RTTI ?
От: Анатолий Широков СССР  
Дата: 28.07.09 15:07
Оценка: +1
А>Смущает то, что, для решения такой, казалось бы простой задачи приходится использовать тяжелую артиллерию — RTTI.
А>Можно ли как-то сравнить PImpl-ы, не использую dynamic_cast<>(), typeid(), и уж тем более самопальные заменители RTTI ?

А вы обяжите потомков Impl_base возвращать хеш (например, md5) вычисленный по состоянию объекта:

class Impl_base 
{
public:
    virtual std::string hash() const = 0;
};


и сравнивайте уже его:

bool PImpl::operator == (const PImpl &other) const
{
  return m_pImpl.hash() == other.m_pImpl.hash();
}
Re[2]: PImpl и сравнение: возможно ли без RTTI ?
От: Аноним  
Дата: 28.07.09 15:11
Оценка:
Очень интерессное решение, впервые такое вижу.
Только я не заню, что такое Flat memory? Можете объяснить? Или направте, пожалуйста, к источнику.
Re: PImpl и сравнение: возможно ли без RTTI ?
От: Bell Россия  
Дата: 29.07.09 02:10
Оценка: 2 (1)
Здравствуйте, Аноним, Вы писали:

Вот здесь было обсуждение подобной задачи: http://rsdn.ru/forum/cpp.applied/1930652.aspx
Автор: _doctor
Дата: 01.06.06
Любите книгу — источник знаний (с) М.Горький
Re[2]: PImpl и сравнение: возможно ли без RTTI ?
От: ChainEG  
Дата: 29.07.09 06:19
Оценка:
Здравствуйте, Bell, Вы писали:

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

Я зарегистрировался

B>Вот здесь было обсуждение подобной задачи: http://rsdn.ru/forum/cpp.applied/1930652.aspx
Автор: _doctor
Дата: 01.06.06

Большое спасибо, очень интересно
Re[2]: PImpl и сравнение: возможно ли без RTTI ?
От: ChainEG  
Дата: 29.07.09 06:42
Оценка:
Здравствуйте, superman, Вы писали:

S>как насчет двойной диспечеризации?

Большое спасибо за пример. Когда-то читал про это, но совсем забыл. Теперь вспомнил, буду применять.

S>Да, а вообще накой вам эта иерархия пиплов? ИМХО слишком сложно.


class Impl_Animal {
 public:
  virtual void Run()=0;
};

class Impl_Cat: public Impl_Animal  {
 public:
  virtual void Run() { /*something to do*/ }
};

class Impl_Dog: public Impl_Animal  {
 public:
  virtual void Run() { /*something to do*/ }
};

class Impl_Mouse: public Impl_Animal  { /*......*/ };
class Impl_Snake: public Impl_Animal  { /*......*/ };

class Animal {
 public:
  void Run() { m_pImpl->Run(); }

 private:
  Impl_Animal *m_pImpl;  
};


Итого, у нас все животные имеют одинаковый тип: Animal, тем не менее поведение у них разное. То есть, можно хранить разных зверей в одном контейнере.
Естественно, есть нюансы, связанные с копированием и разрушением этих объектов, но это уже другая тема
Re[3]: PImpl и сравнение: возможно ли без RTTI ?
От: Bell Россия  
Дата: 29.07.09 06:52
Оценка:
Здравствуйте, ChainEG, Вы писали:

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

CEG>Я зарегистрировался
Любите книгу — источник знаний (с) М.Горький
Re[3]: PImpl и сравнение: возможно ли без RTTI ?
От: Vain Россия google.ru
Дата: 29.07.09 09:13
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Очень интерессное решение, впервые такое вижу.

А>Только я не заню, что такое Flat memory? Можете объяснить? Или направте, пожалуйста, к источнику.
Тип адресации такой, здесь или здесь можно почитать. Суть в том, чтобы адрес был полный, т.е. уникальный, чтобы являться ключом в операциях сравнения.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: PImpl и сравнение: возможно ли без RTTI ?
От: ChainEG  
Дата: 29.07.09 10:36
Оценка:
Здравствуйте, Vain, Вы писали:

V>
V>  virtual void* GetClassId() const
V>  {
V>     static int uniqAddressVar = 0;
V>     return &uniqAddressVar;
V>  }
V>};
V>

V>Работает если Flat memory.

А почему не будет работать, если не Flat memory?

У каждого класса есть своя uniqAddressVar. Если классы разные, то uniqAddressVar у них разные, и адреса uniqAddressVar тоже разные. А если классы одинаковые, то GetClassId() вернет адрес одного и того же uniqAddressVar.
Re[3]: PImpl и сравнение: возможно ли без RTTI ?
От: Vain Россия google.ru
Дата: 29.07.09 14:16
Оценка:
Здравствуйте, ChainEG, Вы писали:

CEG>А почему не будет работать, если не Flat memory?

CEG>У каждого класса есть своя uniqAddressVar. Если классы разные, то uniqAddressVar у них разные, и адреса uniqAddressVar тоже разные. А если классы одинаковые, то GetClassId() вернет адрес одного и того же uniqAddressVar.
Здесь
Автор: Vain
Дата: 29.07.09

В общем случае, это зависит от реализации адресации. К примеру, перед использованием указателей, надо указать сегмент/селектор памяти, тогда одним void* — не обойтись.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[4]: PImpl и сравнение: возможно ли без RTTI ?
От: ChainEG  
Дата: 30.07.09 08:51
Оценка:
Здравствуйте, Vain, Вы писали:

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


CEG>>А почему не будет работать, если не Flat memory?

V>Здесь
Автор: Vain
Дата: 29.07.09

V>В общем случае, это зависит от реализации адресации. К примеру, перед использованием указателей, надо указать сегмент/селектор памяти, тогда одним void* — не обойтись.
Еще раз прочитал Википедию. Ответ, видимо, кроется в середине статьи в следующих строчках:

Segmented memory model:
* .............
* Pages can overlap / poor resource protection and isolation
* Many to one address translation correspondence: Many segment:offset combinations resolve to the same physical address


То есть, в сегментной модели один и тот же адрес может быть представлен различными комбинациями сегмент:смещение. Выходит, два указателя p1 и p2, имеющие различные значения, могут указывать на один о тот же объект.

Но вот что говорит стандарт по поводу сравнения указателей:

3.9.2.4
A void* shall be able to hold any object pointer.

5.9.2
— If two pointers p and q of the same type point to the same object or function, or both point one past the end of the same array, or are both null, then p<=q and p>=q both yield true and p<q and p>q both yield false.

5.10.1.
Pointers to objects or functions of the same type (after pointer conversions) can be compared for equality. Two pointers of the same type compare equal if and only if they are both null, both point to the same function, or both represent the same address (3.9.2).


Получается, C++ гарантирует, что p1==p2 тогда и только тогда, когда p1 и p2 указывают на один и тот же объект. И наплевать, что p1 и p2 имеют разное битовое представление. Это забота компилятора или процессора — понять, ссылаются ли эти указатели на один объект, или на разные, и вернуть мне true или false.
Re[5]: PImpl и сравнение: возможно ли без RTTI ?
От: Vain Россия google.ru
Дата: 30.07.09 09:33
Оценка:
Здравствуйте, ChainEG, Вы писали:

CEG>>>А почему не будет работать, если не Flat memory?

V>>Здесь
Автор: Vain
Дата: 29.07.09

V>>В общем случае, это зависит от реализации адресации. К примеру, перед использованием указателей, надо указать сегмент/селектор памяти, тогда одним void* — не обойтись.
CEG>Еще раз прочитал Википедию. Ответ, видимо, кроется в середине статьи в следующих строчках:
CEG>

CEG>Segmented memory model:
CEG> * .............
CEG> * Pages can overlap / poor resource protection and isolation
CEG> * Many to one address translation correspondence: Many segment:offset combinations resolve to the same physical address

CEG>То есть, в сегментной модели один и тот же адрес может быть представлен различными комбинациями сегмент:смещение. Выходит, два указателя p1 и p2, имеющие различные значения, могут указывать на один о тот же объект.
..и наоборот.
CEG>Но вот что говорит стандарт по поводу сравнения указателей:
CEG>Получается, C++ гарантирует, что p1==p2 тогда и только тогда, когда p1 и p2 указывают на один и тот же объект. И наплевать, что p1 и p2 имеют разное битовое представление. Это забота компилятора или процессора — понять, ссылаются ли эти указатели на один объект, или на разные, и вернуть мне true или false.
Некоторые пункты могут и не выполняться под конкретным компилятором и платформой.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: PImpl и сравнение: возможно ли без RTTI ?
От: Erop Россия  
Дата: 30.07.09 16:28
Оценка:
Здравствуйте, Vain, Вы писали:

V>Работает если Flat memory.


А разве равенство указателей не гарантирует совпадение объектов в любой модели?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: PImpl и сравнение: возможно ли без RTTI ?
От: Кодт Россия  
Дата: 04.08.09 12:56
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

Секундочку! У нас pimpl или полиморфизм?

Для pimpl самого по себе — операция сравнения ничем не отличается от любой другой функции, засунутой в реализацию.

А для полиморфных объектов — тут, безусловно, мы попадаем на мультиметод.
Дальше возникают варианты, как сделать его
1) правильным, с т.з. предметной области
2) дешёвым
3) расширяемым (если множество классов не зафиксировано)

Правильность — это, в первую очередь, соблюдение аксиоматики операции сравнения:
— рефлексивность — x==x
— симметрия — x==y <=> y==x
— транзитивность — x==y && y==z <=> x==z

Для классов, особенно, участвующих в наследовании, требуется решить: сравнимы ли разнотипные объекты (из разных ветвей иерархии, а также предок с наследником).

Проще всего, когда неравенство типов влечёт неравенство объектов.
Тогда мы сравниваем rtti (встроенное или рукодельное) и, в случае равенства, делаем допущение
class IImpl
{
public:
    virtual bool IsEqual(IImpl const& other) const = 0; // typeid(*this) == typeid(other)
};

class SomeImpl : public IImpl
{
    bool IsEqual(SomeImpl const& other) const { ..... }
    virtual bool IsEqual(IImpl const& other) const
    {
        return IsEqual(static_cast<SomeImpl const&>(other)); // или dynamic_cast для уверенности
    }
};

class Facade
{
    IImpl* m_impl;
public:
    bool operator == (Facade const& other) const
    {
        return typeid(*m_impl) == typeid(*other.m_impl) && m_impl->IsEqual(*other.m_impl);
    }
};


Но, скажем, если у нас есть прямоугольники и квадраты (кто от кого наследует, и наследует ли вообще — сейчас неважно).
Естественно считать, что прямоугольник со сторонами X,X равен квадрату со стороной X.
А все фигуры с нулевыми размерами — вообще равны между собой.

Реализовать мультиметод можно кучей разных способов. Наиболее популярный — двойная диспетчеризация, хотя для обеспечения симметрии там придётся потратить силы.

Если множество классов невелико, и они не разбросаны по системе, то я бы предпочёл сделать паттерн-матчинг.
template<class X> bool is(IImpl const& x) { return typeid(X) == typeid(x); }

template<class X, class Y> bool eq(IImpl const& x, IImpl const& y) { return AreEqual(static_cast<X>(x), static_cast<Y>(y)); }
// где AreEqual - перегруженная функция, реализующая то самое сравнение

bool operator == (IImpl const& a, IImpl const& b)
{
    if( is<Rectangle>(a) && is<Rectangle>(b) ) return eq<Rectangle,Rectangle>(a,b);
    
    if( is<Square>(a)    && is<Square>(b)    ) return eq<Square,Square>(a,b);
    
    if( is<Rectangle>(a) && is<Square>(b)    ) return eq<Rectangle,Square>(a,b);
    if( is<Rectangle>(b) && is<Square>(a)    ) return eq<Rectangle,Square>(b,a); // воспользовались симметрией
    
    return false;
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1207>>
Перекуём баги на фичи!
Re[4]: PImpl и сравнение: возможно ли без RTTI ?
От: Кодт Россия  
Дата: 04.08.09 13:05
Оценка:
Здравствуйте, Vain, Вы писали:

V>В общем случае, это зависит от реализации адресации. К примеру, перед использованием указателей, надо указать сегмент/селектор памяти, тогда одним void* — не обойтись.


Да просто будет void far*, обеспечивающий глобальную уникальность адреса — а void near* (только смещение без селектора) это для жмотов, экономящих на спичках.
Под досом в large модели жили же как-то?
... << RSDN@Home 1.2.0 alpha 4 rev. 1207>>
Перекуём баги на фичи!
Re[5]: PImpl и сравнение: возможно ли без RTTI ?
От: Erop Россия  
Дата: 04.08.09 22:01
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Под досом в large модели жили же как-то?

А разве там можнобыло сравнить два укащателя на разные сегменты и состоящие только из смещения...
По идее, если можешь указатели разыменовать, то можешь и сравнить...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.