Показаны сообщения с ярлыком thoughts. Показать все сообщения
Показаны сообщения с ярлыком thoughts. Показать все сообщения

среда, 2 января 2008 г.

О ссылающихся друг на друга объектах

Очень часто возникает ситуация, при которой объект, объявленный раньше, должен вызывать метод объекта, объявленного позже. Но поменять объявления местами не представляется возможным, ибо "нижестоящий" по коду ссылается на "вышестоящего".

Пример:

class foo
{
public:
void test( bar * b ) { b->print( "foo" ); }
};

class bar
{
public:
void print( const char * txt ) { printf_s( "%s\n", txt ); }
private:
foo m_obj;
};
_Winnie C++ Colorizer

При попытки скомпилировать это, компилятор пошлёт к такой-то матери. Ну и понятно, ведь на момент компиляции foo, нет никакой информации о bar. Это же не позволяет использовать обычные указатели на методы класса.

Можно попытаться выкрутиться, используя интерфейсы:

struct i_bar
{
virtual void print( const char * txt ) = 0;
};

class foo
{
public:
void test( i_bar * b ) { b->print( "foo" ); }
};

class bar : public i_bar
{
public:
void print( const char * txt ) { printf_s( "%s\n", txt ); }
private:
foo m_obj;
};
_Winnie C++ Colorizer

Данный код скомпилиться и будет работать. Но этот подход требует создание "костылей", что не радует глаз. К тому же нарушается иерархия. foo приходиться знать о bar, хотя знать о нём он не обязан. Всё что нужно - это вызов некой "абстрактной" функции/метода. А чья она - это уже не важно.

Можно "разнести" объявление и реализацию классов:
// bar.h
#include "foo.h"

class bar
{
public:
void print( const char * txt ) { printf_s( "%s\n", txt ); }
private:
foo m_obj;
};

// foo.h
class bar;
class foo
{
public:
void test( bar * b );
};

// foo.cpp
#include "foo.h"
#include "bar.h"

void foo::test( bar * b )
{
b->print( "foo" );
}
_Winnie C++ Colorizer

Но раскидывать код по файлам не всегда бывает удобно. К тому же снова идёт нарушении иерархии, как в предидущем пункте. Но как бы то ни было, этот метод очень распространён. И я пользовался им до недавнего времени.

Пока не начала курить boost =)
typedef boost::function< void( const char * ) > boost_func;

class foo
{
public:
void test( boost_func & func ) { func( "foo" ); }
};

class bar
{
public:
void print( const char * txt ) { printf_s( "%s\n", txt ); }
private:
foo m_obj;
};


int _tmain( int, char * )
{
foo f;
bar b;

f.test( boost_func( boost::bind( &bar::print, &b, _1 ) ) );

return 0;
}
_Winnie C++ Colorizer

Вуаля! boost::bind + boost::function решает все проблемы. Раскидывать ничего не надо. К томуже foo не приходиться ничего знает о bar. Одни плюсы =)

Вот только я ещё не до конца понял, как это штука работает. Но работает - факт.

суббота, 29 декабря 2007 г.

мысли вслух

Иногда так хочеться написать:

std::vector< const some_type & > foo

А низя =(