LINUX.ORG.RU

Вложенность классов и предварительное объявление


0

0

Есть такой код:

data.h
======
class Data : public Object {
public:
  typedef boost::intrusive_ptr<Data>;

  class Visitor {
  public:
    virtual ~Visitor() {}

    operator()(Measure::Ptr measure) {}
  };

  virtual void apply_visitor(Visitor &visitor) = 0;
};

measure.h
=========
class Measure : public Data {
public:
  typedef boost::intrusive_ptr<Measure> Ptr;

  void apply_visitor(Visitor &visitor)
  {
    visitor(Ptr(this));
  }
};

Пояснения:
Класс Object реализует подсчет ссылок и предназначен для использования совместно с boost::intrusive_ptr<>.
Разумеется, этот код не компилируется, т.к. в момент обработки data.h  компилятор ничего не знает про Measure::Ptr и, следовательно, не компилируется класс Data::Visitor.

Что делать?

P.S. В operator() класса Visitor можно передавать ссылку на Measure - для этого достаточно в data.h добавить строку class Measure;, но хочется передавать имеено Measure::Ptr.

Ответ на: комментарий от klalafuda

В чем же он broken? Как вариант, можно изменить operator() так: virtual void operator(boost::intrusive_ptr<Measure> ), но некрасиво ведь.

syomin
() автор топика
Ответ на: комментарий от syomin

А почему обязательно virtual? Можно и не-virtual метод вынести в файл реализации - тогда не будет inlining, но вызов будет обычным, без virtual overhead.

Хотя это действительно broken - ни к чему базовому классу знать о конкретных наследниках. А если уж действительно так сильно хочется tight coupling - так и запихай их в один заголовочный файл, и все будет.

int19h ★★★★
()
Ответ на: комментарий от syomin

>В чем же он broken?

А вы посмотрите на иерархию классов.

>Как вариант, можно изменить operator() так: virtual >void >operator(boost::intrusive_ptr<Measure> ), но некрасиво ведь.

Да, это уже костыль.

KIV
()
Ответ на: комментарий от int19h

> В общем случае - нужно сделать uncoupling классов Data и Measure.

А понятным языком можно?

syomin
() автор топика
Ответ на: комментарий от syomin

>Получается, самое разумное - вынести класс Visitor за пределы класса Data?

Из приведенного кода такое решение напрашивается. Общий контекст не ясен. В каких отношениях состоят Visitor и Data? Поучему-то ведь было решено объявить Visitor в Data?

KIV
()
Ответ на: комментарий от KIV

Visitor - реализация шаблона (паттерна) проектирования "Посетитель". Полное описание есть в GoF.

Если очень кратко, то смысл в следующем. От Data наследуется несколько классов, а не только Measure. Вся эта хренотень - часть сетевой библиотеки, а описанные выше классы соответствуют различным типам сообщений, которые могут быть переданы по сети. Код, который использует библиотеку, при получении данных по сети получает указатель на Data, а дальше должен сам разбираться, что ему пришло и как это обработать. Для этого делается наследник от Visitor и в нем переопределяются операторы вызова, а потом выполняется apply_visitor. В зависимости от фактического типа объекта, вызывается тот или иной вариант оператора ().

Класс Visitor был объявлен внутри класса Data из-за того, что фактически есть еще несколько иерархий классов и там тоже есть свои visitor'ы.

syomin
() автор топика
Ответ на: комментарий от MKuznetsov

> а при чём и нахрена тут Visitor ?
> просто слово понравилось что-ли ???

Если честно, не понял сути претензий.
В данном случае название отражает назначение класса. Другое дело, что не стоило, его, наверное, помещать внутрь Data.

syomin
() автор топика
Ответ на: комментарий от syomin

Я так и знал что не все так просто :)

>Класс Visitor был объявлен внутри класса Data из-за того, что фактически есть еще несколько иерархий классов и там тоже есть свои visitor'ы.

Просто из приведенного тобой кода естественно всего этого не видно :) Но я бы не стал делать в проекте сущностей с одним и тем же именем. Если только какие-нибудь мелкие утилитарные конструкции, например, енумы ошибок внутри каждого класса.

KIV
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.