Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> "Умная" работа с переменными-членами класса 
:(
    Опции темы
GoldFinch
Дата 20.3.2009, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: 15
Всего: 26



mes, не, в этом случае например в объекте Cone будут не 2 поля с разными именами, а массив или вектор из 2х элементов типа Dimention, для ввода которых надо будет обойти этот массив итератором вызывая Input() 
PM MAIL ICQ   Вверх
mes
Дата 20.3.2009, 13:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(GoldFinch @  20.3.2009,  12:12 Найти цитируемый пост)
mes, не, в этом случае например в объекте Cone будут не 2 поля с разными именами, а массив или вектор из 2х элементов типа Dimention, для ввода которых надо будет обойти этот массив итератором вызывая Input()  

Вы не про то.. я про Ваш субъект Radius. В вашей компоновке операция Input жестко привязана к нему. 
Разницы нет кто из чего состоит. Суть в том что к иерархии субъектов в таком случае нельзя добавить новую операцию, в отличии от подхода с визитором.
(см. пример  с кодом)


Это сообщение отредактировал(а) mes - 20.3.2009, 13:31


--------------------
PM MAIL WWW   Вверх
Lazin
Дата 20.3.2009, 14:33 (ссылка)  | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



накидал пример на скорую руку
Код

#include <iostream>
#include <exception>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container/vector.hpp>


struct length
{
    double value;
    double& operator[] (int ix)
    {
        if (ix != 0) throw std::runtime_error("length operator[] error, index out of range");
        return value;
    }
    length(double x) : value(x) {}
};

struct point
{
    double xyz[3];
    double& operator [] (int ix) 
    {
        if(ix < 0||ix > 2) throw std::runtime_error("point operator[] error, index out of range");
        return xyz[ix]; 
    }  
    point(double x, double y, double z)
    {
        xyz[0] = x;
        xyz[1] = y;
        xyz[2] = z;
    }
};

struct metadata
{
    std::string class_name;
    size_t tag;
    metadata(const char* name, size_t tag) : class_name(name), tag(tag) {}
};

struct BodyAccessor 
{
    virtual void operator () (point& p) const = 0;
    virtual void operator () (length& p) const = 0;
    virtual void operator () (metadata& p) const = 0;
};

struct Body
{
    virtual ~Body() = 0;
    virtual void access(const BodyAccessor&) = 0;
};
Body::~Body() {}



template<class Sequence>
struct GenericBody : Body
{
    metadata traits;
    Sequence sequence;

    typedef Sequence param_type;

    virtual void access(const BodyAccessor& a)
    {
        a(traits);
        boost::fusion::for_each(sequence, a);
    }

    GenericBody( const Sequence& s, const metadata& m ) 
        : traits(m)
        , sequence(s)
    {
    }
};
typedef GenericBody< boost::fusion::vector<point, point> > Line;
typedef GenericBody< boost::fusion::vector<point, length>> Circle;

struct BodyFactory
{
    Body* create_line(const point& a, const point& b)
    {
        return new Line( Line::param_type(a, b), metadata("Line", 1) );
    }

    Body* create_circle(const point& center, const length& radius)
    {
        return new Circle( Circle::param_type(center, radius), metadata("Circle", 1) );
    }
};

struct InputAccessor : BodyAccessor
{
    void operator () (metadata& p) const
    {
        std::cout << "Input params for " << p.class_name << std::endl;
    }
    void operator () (point& p) const
    {
        std::cout << "enter point" << std::endl;
        std::cin >> p[0] >> p[1] >> p[2];
    }
    void operator () (length& p) const
    {
        std::cout << "enter length" << std::endl;
        std::cin >> p[0];
    }
};


struct OutputAccessor : BodyAccessor
{
    void operator () (metadata& p) const
    {
        std::cout << "Print params for " << p.class_name << std::endl;
    }
    void operator () (point& p) const
    {
        std::cout << "point(" << p[0] << ", " << p[1] << ", " << p[2] << ")" << std::endl;;
    }
    void operator () (length& p) const
    {
        std::cout << "length(" << p[0] << ")" << std::endl;
    }
};


int main()
{
    BodyFactory factory;
    Body* line = factory.create_line( point(0, 0, 0), point(0, 0, 0) );
    Body* circle = factory.create_circle( point(0, 0, 0), length(10) );
    InputAccessor in;
    OutputAccessor out;

    std::cout << " line " << std::endl; 
    line->access(out);
    line->access(in);
    line->access(out);
    
    std::cout << " circle " << std::endl; 
    circle->access(out);
    circle->access(in);
    circle->access(out);
    system("pause");
}

суть в том, чтобы вместо иерархии объектов, использовать композицию, в данном случае я использовал boost::fusion для хранения структуры объекта. Примитивные типы для данного примера это point, line и metadata. Объект класса metadata хранит информацию о классе объекта. В принципе, можно добавить метаданные для каждого параметра, каждого объекта, для этого нужно вместо boost::fusion::vector использовать что-то вроде boost::fusison::map, но мне лень это делать)

Добавлено через 3 минуты и 2 секунды
в принципе, объект класса metadata в каждом новом объекте GenericBody  это лишний оверхэд, достаточно создать один объект metadata на каждый "класс"(вариант инстанциирования GenericBody) и в GenericBody хранить только ссылку на такой глобальный объект

Добавлено через 6 минут и 40 секунд
примерно так:
Код

#include <iostream>
#include <exception>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container/vector.hpp>


struct length
{
    double value;
    double& operator[] (int ix)
    {
        if (ix != 0) throw std::runtime_error("length operator[] error, index out of range");
        return value;
    }
    length(double x) : value(x) {}
};

struct point
{
    double xyz[3];
    double& operator [] (int ix) 
    {
        if(ix < 0||ix > 2) throw std::runtime_error("point operator[] error, index out of range");
        return xyz[ix]; 
    }  
    point(double x, double y, double z)
    {
        xyz[0] = x;
        xyz[1] = y;
        xyz[2] = z;
    }
};

struct metadata
{
    std::string class_name;
    size_t tag;
    metadata(const char* name, size_t tag) : class_name(name), tag(tag) {}
};

struct BodyAccessor 
{
    virtual void operator () (point& p) const = 0;
    virtual void operator () (length& p) const = 0;
    virtual void operator () (const metadata& p) const = 0;
};

struct Body
{
    virtual ~Body() = 0;
    virtual void access(const BodyAccessor&) = 0;
};
Body::~Body() {}



template<class Sequence>
struct GenericBody : Body
{
    const metadata &traits;
    Sequence sequence;

    typedef Sequence param_type;

    virtual void access(const BodyAccessor& a)
    {
        a(traits);
        boost::fusion::for_each(sequence, a);
    }

    GenericBody( const Sequence& s, const metadata& m ) 
        : traits(m)
        , sequence(s)
    {
    }
};
typedef GenericBody< boost::fusion::vector<point, point> > Line;
typedef GenericBody< boost::fusion::vector<point, length>> Circle;

struct BodyFactory
{
    metadata class_line, class_circle; 
    BodyFactory()
        : class_line("line", 1)
        , class_circle("circle", 2)
    {
    }
    Body* create_line(const point& a, const point& b)
    {
        return new Line( Line::param_type(a, b), class_line );
    }

    Body* create_circle(const point& center, const length& radius)
    {
        return new Circle( Circle::param_type(center, radius), class_circle );
    }
};

struct InputAccessor : BodyAccessor
{
    void operator () (const metadata& p) const
    {
        std::cout << "Input params for " << p.class_name << std::endl;
    }
    void operator () (point& p) const
    {
        std::cout << "enter point" << std::endl;
        std::cin >> p[0] >> p[1] >> p[2];
    }
    void operator () (length& p) const
    {
        std::cout << "enter length" << std::endl;
        std::cin >> p[0];
    }
};


struct OutputAccessor : BodyAccessor
{
    void operator () (const metadata& p) const
    {
        std::cout << "Print params for " << p.class_name << std::endl;
    }
    void operator () (point& p) const
    {
        std::cout << "point(" << p[0] << ", " << p[1] << ", " << p[2] << ")" << std::endl;;
    }
    void operator () (length& p) const
    {
        std::cout << "length(" << p[0] << ")" << std::endl;
    }
};


int main()
{
    BodyFactory factory;
    Body* line = factory.create_line( point(0, 0, 0), point(0, 0, 0) );
    Body* circle = factory.create_circle( point(0, 0, 0), length(10) );
    InputAccessor in;
    OutputAccessor out;

    std::cout << " line " << std::endl; 
    line->access(out);
    line->access(in);
    line->access(out);
    
    std::cout << " circle " << std::endl; 
    circle->access(out);
    circle->access(in);
    circle->access(out);
    system("pause");
}



PM MAIL Skype GTalk   Вверх
GoldFinch
Дата 20.3.2009, 14:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: 15
Всего: 26



Lazin, выглядит страшно, а работает наверное еще страшнее,
с посетителем куда как лучше, и накладных расходов на память 0
к тому же то что у вас  - несколько не соответствует задаче ТС, нужно хранить размеры а не координаты
PM MAIL ICQ   Вверх
Lazin
Дата 20.3.2009, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(GoldFinch @  20.3.2009,  14:44 Найти цитируемый пост)
с посетителем куда как лучше, и накладных расходов на память 0

а это и есть паттерн visitor

Цитата(GoldFinch @  20.3.2009,  14:44 Найти цитируемый пост)
нужно хранить размеры а не координаты

мой пример можно обобщит хоть на хранение килограммов и амперов, смысл в том, что у нас есть набор параметров разных типов(в данном случае это координаты точек и длины), и из них мы строим еще больше классов(линии и окружности), каждый такой класс(GenericBody) имеет ссылку на описатель класса и набор параметров, набор параметров хранится в boost::fusion::vector, что эквивалентно использованию обычной структуры, так-что утверждение
Цитата(GoldFinch @  20.3.2009,  14:44 Найти цитируемый пост)
выглядит страшно, а работает наверное еще страшнее

неверно smile

Добавлено через 5 минут и 19 секунд
по памяти это +4 байта на каждый объект GenericBody и еще +4 байта на указатель на таблицу вирт. функций, по сравнению с обычными структурами
по скорости, это один вызов виртуальной ф-ии(в случае если visitor получает указатель на весь класс сразу), против N вызовов(N - количество параметров класса), разница будет незаметна...
PM MAIL Skype GTalk   Вверх
vinter
Дата 20.3.2009, 15:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 13
Всего: 56



Цитата(Lazin @  20.3.2009,  15:33 Найти цитируемый пост)
накидал пример на скорую руку

 smile  страшно представить, что ты пишешь не на скорую  smile 


--------------------
Мой блог
PM MAIL WWW   Вверх
mes
Дата 20.3.2009, 15:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Lazin, Ваш пример хорош, когда Body является просто контейнером параметров. Однако фигура это не просто набор параметров..
к примеру, попробуйте в Вашем примере, применить операцию Draw () smile 

Это сообщение отредактировал(а) mes - 20.3.2009, 15:30


--------------------
PM MAIL WWW   Вверх
Lazin
Дата 20.3.2009, 15:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



мой пример хорош, когда код должен хорошо масштабировться в сторону добавления новых классов, так-как все "методы"(объекты клaсса BodyAccessor) не нужно реализовывать для каждого класса. В принципе можно получить любую функциональность, но, если таких классов мало, то проще использовать стандартный подход.
PM MAIL Skype GTalk   Вверх
mes
Дата 20.3.2009, 15:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Lazin @  20.3.2009,  14:33 Найти цитируемый пост)
мой пример хорош, когда код должен хорошо масштабировться в сторону добавления новых классов, так-как все "методы"(объекты клaсса BodyAccessor) не нужно реализовывать для каждого класса. В принципе можно получить любую функциональность, но, если таких классов мало, то проще использовать стандартный подход.

согласен, но сказал бы так:  его хорошо использовать наряду со стандартным подходом, в случае если предполагается также добавление новых классов (например посредством плагина).
т.е условная иерархия такая : Line, Cirlce, Quad, Generic. 

Это сообщение отредактировал(а) mes - 20.3.2009, 15:39


--------------------
PM MAIL WWW   Вверх
Lazin
Дата 20.3.2009, 16:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(mes @  20.3.2009,  15:37 Найти цитируемый пост)
т.е условная иерархия такая : Line, Cirlce, Quad, Generic.

я бы не сказал, тогда придется вручную реализовывать метод accept для всех вариантов: Line, Circle, Quad etc, в общем тогда проще использовать стандартный подход, и быдлокодить всю иерархию игнорируя тот факт, что объекты Line, Circle, Quad etc, состоят из небольшого набора элементов.
Конечно мой пример далек от совершенства, его еще можно сильно улучшить. Но с точки зрения архитектуры, он лучше чем иерархия классов.
PM MAIL Skype GTalk   Вверх
mes
Дата 20.3.2009, 16:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Lazin @  20.3.2009,  15:05 Найти цитируемый пост)
я бы не сказал, тогда придется вручную реализовывать метод accept для всех вариантов: Line, Circle, Quad etc, в общем тогда проще использовать стандартный подход, и быдлокодить всю иерархию игнорируя тот факт, что объекты Line, Circle, Quad etc, состоят из небольшого набора элементов.
Конечно мой пример далек от совершенства, его еще можно сильно улучшить. Но с точки зрения архитектуры, он лучше чем иерархия классов. 

покажите пример удобной реализации функции Draw() для Вашего примера, и если ее недостатки не перекроют достоинства Вашей модели, тогда я с Вами соглашусь.  smile 

Это сообщение отредактировал(а) mes - 20.3.2009, 16:22


--------------------
PM MAIL WWW   Вверх
Lazin
Дата 20.3.2009, 17:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(mes @  20.3.2009,  16:21 Найти цитируемый пост)
покажите пример удобной реализации функции Draw() для Вашего примера, и если ее недостатки не перекроют достоинства Вашей модели, тогда я с Вами соглашусь.

самый простой вариант, можно добавить вирт. ф-ю в класс Body, и специализировать ее для каждого шаблона, но, нужно писать ф-ю для каждой специализации, что плохо
Код

#include <iostream>
#include <exception>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container/vector.hpp>


struct DrawContext
{
};

struct length
{
    double value;
    double& operator[] (int ix)
    {
        if (ix != 0) throw std::runtime_error("length operator[] error, index out of range");
        return value;
    }
    length(double x) : value(x) {}
};

struct point
{
    double xyz[3];
    double& operator [] (int ix) 
    {
        if(ix < 0||ix > 2) throw std::runtime_error("point operator[] error, index out of range");
        return xyz[ix]; 
    }  
    point(double x, double y, double z)
    {
        xyz[0] = x;
        xyz[1] = y;
        xyz[2] = z;
    }
};

struct metadata
{
    std::string class_name;
    size_t tag;
    metadata(const char* name, size_t tag) : class_name(name), tag(tag) {}
};

struct BodyAccessor 
{
    virtual void operator () (point& p) const = 0;
    virtual void operator () (length& p) const = 0;
    virtual void operator () (const metadata& p) const = 0;
};

struct Body
{
    virtual ~Body() = 0;
    virtual void access(const BodyAccessor&) = 0;
    virtual void draw(DrawContext& dc) = 0;
};
Body::~Body() {}



template<class Sequence>
struct GenericBody : Body
{
    const metadata &traits;
    Sequence sequence;

    typedef Sequence param_type;

    virtual void access(const BodyAccessor& a)
    {
        a(traits);
        boost::fusion::for_each(sequence, a);
    }

    GenericBody( const Sequence& s, const metadata& m ) 
        : traits(m)
        , sequence(s)
    {
    }
    virtual void draw(DrawContext& dc);
};

///line class
typedef GenericBody< boost::fusion::vector<point, point> > Line;
void Line::draw(DrawContext& dc)
{
    std::cout << "MoveTo(" 
              << boost::fusion::at_c<0>(sequence)[0] << ", " 
              << boost::fusion::at_c<0>(sequence)[1] << ");" << std::endl;
    std::cout << "LineTo(" 
              << boost::fusion::at_c<1>(sequence)[0] << ", " 
              << boost::fusion::at_c<1>(sequence)[1] << ");" << std::endl;
}


typedef GenericBody< boost::fusion::vector<point, length> > Circle;
void Circle::draw(DrawContext& dc)
{
    std::cout << "MoveTo(" 
              << boost::fusion::at_c<0>(sequence)[0] << ", " 
              << boost::fusion::at_c<0>(sequence)[1] << ");" << std::endl;
    std::cout << "DrawCircle(" 
              << boost::fusion::at_c<1>(sequence)[0] << ");" << std::endl;
}

struct BodyFactory
{
    metadata class_line, class_circle; 
    BodyFactory()
        : class_line("line", 1)
        , class_circle("circle", 2)
    {
    }
    Body* create_line(const point& a, const point& b)
    {
        return new Line( Line::param_type(a, b), class_line );
    }

    Body* create_circle(const point& center, const length& radius)
    {
        return new Circle( Circle::param_type(center, radius), class_circle );
    }
};

struct InputAccessor : BodyAccessor
{
    void operator () (const metadata& p) const
    {
        std::cout << "Input params for " << p.class_name << std::endl;
    }
    void operator () (point& p) const
    {
        std::cout << "enter point" << std::endl;
        std::cin >> p[0] >> p[1] >> p[2];
    }
    void operator () (length& p) const
    {
        std::cout << "enter length" << std::endl;
        std::cin >> p[0];
    }
};


struct OutputAccessor : BodyAccessor
{
    void operator () (const metadata& p) const
    {
        std::cout << "Print params for " << p.class_name << std::endl;
    }
    void operator () (point& p) const
    {
        std::cout << "point(" << p[0] << ", " << p[1] << ", " << p[2] << ")" << std::endl;;
    }
    void operator () (length& p) const
    {
        std::cout << "length(" << p[0] << ")" << std::endl;
    }
};


int main()
{
    BodyFactory factory;
    Body* line = factory.create_line( point(0, 0, 0), point(0, 0, 0) );
    Body* circle = factory.create_circle( point(0, 0, 0), length(10) );
    InputAccessor in;
    OutputAccessor out;

    std::cout << " line " << std::endl; 
    line->access(out);
    line->access(in);
    line->access(out);
    
    std::cout << " circle " << std::endl; 
    circle->access(out);
    circle->access(in);
    circle->access(out);

    DrawContext dc;
    circle->draw(dc);
    line->draw(dc);
    system("pause");
}


Добавлено через 41 секунду
но, можно это сделать и по другому)
PM MAIL Skype GTalk   Вверх
mes
Дата 20.3.2009, 17:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Lazin @  20.3.2009,  16:16 Найти цитируемый пост)
но, можно это сделать и по другому) 

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


--------------------
PM MAIL WWW   Вверх
Lazin
Дата 20.3.2009, 17:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



я думал не специализировать для каждого GenericBody ф-ю draw, а просто реализовать ее в виде отдельного объекта и передавать ее в GenericBody в качестве параметра шаблона, сейчас покажу...

Добавлено через 10 минут и 35 секунд
примерно так...
Код

#include <iostream>
#include <exception>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container/vector.hpp>



struct length
{
    double value;
    double& operator[] (int ix)
    {
        if (ix != 0) throw std::runtime_error("length operator[] error, index out of range");
        return value;
    }
    const double& operator[] (int ix) const
    {
        if (ix != 0) throw std::runtime_error("length operator[] error, index out of range");
        return value;
    }
    length(double x) : value(x) {}
};

struct point
{
    double xyz[3];
    double& operator [] (int ix)
    {
        if(ix < 0||ix > 2) throw std::runtime_error("point operator[] error, index out of range");
        return xyz[ix]; 
    }  
    const double& operator [] (int ix) const
    {
        if(ix < 0||ix > 2) throw std::runtime_error("point operator[] error, index out of range");
        return xyz[ix]; 
    }  
    point(double x, double y, double z)
    {
        xyz[0] = x;
        xyz[1] = y;
        xyz[2] = z;
    }
};

struct DrawContext
{
    void LineTo(const point& p)
    {
        std::cout << "LineTo(" << p[0] << ", " << p[1] << ");" << std::endl;
    }

    void MoveTo(const point& p)
    {
        std::cout << "MoveTo(" << p[0] << ", " << p[1] << ");" << std::endl;
    }

    void DrawCircle(const length& l)
    {
        std::cout << "DrawCircle(" << l[0] << ");" << std::endl;
    }
};

struct metadata
{
    std::string class_name;
    size_t tag;
    metadata(const char* name, size_t tag) : class_name(name), tag(tag) {}
};

struct BodyAccessor 
{
    virtual void operator () (point& p) const = 0;
    virtual void operator () (length& p) const = 0;
    virtual void operator () (const metadata& p) const = 0;
};

struct Body
{
    virtual ~Body() = 0;
    virtual void access(const BodyAccessor&) = 0;
    virtual void draw(DrawContext& dc) = 0;
};
Body::~Body() {}



template<class Sequence, class DrawFn>
struct GenericBody : Body
{
    const metadata &traits;
    Sequence sequence;

    typedef Sequence param_type;

    virtual void access(const BodyAccessor& a)
    {
        a(traits);
        boost::fusion::for_each(sequence, a);
    }

    GenericBody( const Sequence& s, const metadata& m ) 
        : traits(m)
        , sequence(s)
    {
    }
    virtual void draw(DrawContext& dc)
    {
        DrawFn draw_fn;
        draw_fn(dc, sequence);
    }
};

typedef boost::fusion::vector<point, point>  line_sequence_type;
typedef boost::fusion::vector<point, length> circle_sequence_type;

struct DrawLine
{
    void operator()(DrawContext& dc, const line_sequence_type& line)
    {
        dc.MoveTo(boost::fusion::at_c<0>(line));
        dc.LineTo(boost::fusion::at_c<1>(line));
    }
};

struct DrawCircle
{
    void operator()(DrawContext& dc, const circle_sequence_type& circle)
    {
        dc.MoveTo(boost::fusion::at_c<0>(circle));
        dc.DrawCircle(boost::fusion::at_c<1>(circle));
    }
};
///line class
typedef GenericBody< line_sequence_type, DrawLine > Line;


typedef GenericBody< circle_sequence_type, DrawCircle > Circle;

struct BodyFactory
{
    metadata class_line, class_circle; 
    BodyFactory()
        : class_line("line", 1)
        , class_circle("circle", 2)
    {
    }
    Body* create_line(const point& a, const point& b)
    {
        return new Line( Line::param_type(a, b), class_line );
    }

    Body* create_circle(const point& center, const length& radius)
    {
        return new Circle( Circle::param_type(center, radius), class_circle );
    }
};

struct InputAccessor : BodyAccessor
{
    void operator () (const metadata& p) const
    {
        std::cout << "Input params for " << p.class_name << std::endl;
    }
    void operator () (point& p) const
    {
        std::cout << "enter point" << std::endl;
        std::cin >> p[0] >> p[1] >> p[2];
    }
    void operator () (length& p) const
    {
        std::cout << "enter length" << std::endl;
        std::cin >> p[0];
    }
};


struct OutputAccessor : BodyAccessor
{
    void operator () (const metadata& p) const
    {
        std::cout << "Print params for " << p.class_name << std::endl;
    }
    void operator () (point& p) const
    {
        std::cout << "point(" << p[0] << ", " << p[1] << ", " << p[2] << ")" << std::endl;;
    }
    void operator () (length& p) const
    {
        std::cout << "length(" << p[0] << ")" << std::endl;
    }
};


int main()
{
    BodyFactory factory;
    Body* line = factory.create_line( point(0, 0, 0), point(0, 0, 0) );
    Body* circle = factory.create_circle( point(0, 0, 0), length(10) );
    InputAccessor in;
    OutputAccessor out;

    std::cout << " line " << std::endl; 
    line->access(out);
    line->access(in);
    line->access(out);
    
    std::cout << " circle " << std::endl; 
    circle->access(out);
    circle->access(in);
    circle->access(out);

    DrawContext dc;
    circle->draw(dc);
    line->draw(dc);
    system("pause");
}

теперь не обязательно реализовывать метод GenericBody::draw, функторы, занимающиеся отрисовкой фигур можно использовать повторно, либо написать обобщенную версию такого функтора smile 
PM MAIL Skype GTalk   Вверх
Lazin
Дата 20.3.2009, 18:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



в принципе, так можно добавить любую операцию, зависящую от всех данных сразу, например преобразование координат, в то-же время, можно писать обобщенные версии ф-ий, которые работают не со всем объектом целиком, а с его частями, например сериализация, интроспекция. Что-бы написать, к примеру, ф-ю считающую количество вершин геом. фигуры, нужно написать всего один функтор.
PM MAIL Skype GTalk   Вверх
Страницы: (3) Все 1 [2] 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1041 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.