Форум программистов, компьютерный форум CyberForum.ru

Двойная диспетчеризация :) - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 22, средняя оценка - 4.82
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
31.03.2013, 04:27     Двойная диспетчеризация :) #1
Здорова!
Я тут от пытаюсь понять такое понятие взаимодействия классов или хз как назвать, вообщем что такое двойная диспетчеризация. Так сказать. 4 статьи как бы так бегло прочитал но никак нимогу врубиться, что это такое.
Кто может простыми словами объяснить, что это такое?

Добавлено через 49 секунд
Щас голова тяжолая фиг шо варит

Добавлено через 1 минуту
И еще хочу попытаться смоделировать на примере простых классов.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
31.03.2013, 04:27     Двойная диспетчеризация :)
Посмотрите здесь:

C++ двойная буферизация
C++ двойная буферизация
двойная сортировка C++
C++ Двойная загрузка файла
C++ Двойная сумма на C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
31.03.2013, 10:22     Двойная диспетчеризация :) #2
до кучи найдите книгу и прочитайте следующее:
Наиболее эффективное использование C++. 35 новых рекомендаций по улучшению ваших программ и проектов
Автор: Скотт Мейерс
Правило 31. Создавайте функции, виртуальные по отношению более чем к одному объектуhttp://rsdn.ru/res/book/cpp/most_effective_cpp.xml

Сперва одинарная если ее так можно назвать:
Классический пример. Имеем базовый класс Shape и производные от него. У Shape есть виртуальным метод Draw.
В наследниках он как-то имплементится. Имея указатель на Shape вызываем Draw и за счет механизма работы виртуальных функций вызовится правильный метод отрисовки. Т.е. в этом случае не зная на какой именно объект указывает указатель, вызывается правильный метод.

В двойное диспетчеризации нужно тоже самое, только для двух объектов. Т.е. имея два указателя на базовый классы и не зная, на какие именно объекты они ссылаются, нужно вызвать правильную функцию, которая обработала бы вызов в зависимости от конкретных типов этих двух объектов. В книге описывается столкновение
двух объектов. В зависимости от типов объектов столкновения должны по разному обрабатываться.
Т.е клиентский код выглядит как-то так:
Object* obj1 = ...
Object* obj2 = ...
Process(obj1, obj2);

Если объекты - астероиды - то это один способ обработки.
Если объекты - астероид и космический корабль - другой способ.
И т.д.

Вот задача двойной диспетчеризации - это задача нахождения правильной функции обработки столкновения объектов.
Nick Alte
Эксперт С++
1561 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,897
Завершенные тесты: 1
31.03.2013, 13:00     Двойная диспетчеризация :) #3
Есть хороший пример на графических примитивов в каком-нибудь векторном графическом редакторе. Допустим, есть общий предок Shape, от которого наследуются Circle, Square и Triangle (круг, квадрат, треугольник). Нам надо уметь определить площадь пересечения двух фигур. Очевидно, математика такого пересечения зависит от того, какие именно фигуры пересекаются. Но вот сам рисунок представлен в виде коллекции указателей на Shape, где мы можем выбрать произвольно два объекта и поинтересоваться площадью их пересечения. Вот тут-то и вступает в дело двойная диспетчеризация:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Circle;
class Triangle;
class Square;
 
class Shape {
public:
    virtual double getIntersection(const Shape& other) const = 0;  // Функция, которая вызывается для определения площади пересечения
    // Эти функции вычисляют площадь пересечения с конкретной фигурой
    // Для ясности к именам добавлена буква, идентифицирующая класс,
    // но на самом деле необходимости в ней нет, компилятор сориентируется по типам ссылок
    virtual double getIntersectionC(const Circle& c) const = 0;
    virtual double getIntersectionT(const Triangle& t) const = 0;
    virtual double getIntersectionS(const Square& s) const = 0;
};
 
class Circle: public Shape {
public:
    virtual double getIntersection(const Shape& other) const
    {
        return other->getIntersectionС(*this);  // Разворачиваем вызов, надёжно идентифицируя себя как круг
    }
 
    // Реализуем вычисление площади, зная тип нашей фигуры (круг) и второй фигуры
    virtual double getIntersectionC(const Circle& c) const;
    virtual double getIntersectionT(const Triangle& t) const;
    virtual double getIntersectionS(const Square& s) const;    
};
 
// Классы Triangle и Square реализуются аналогично
 
// Получим площадь пересечения фигур, зная их имена
double getIntersectionByNames(const Drawing& drawing, const string& name1, const string& name2)
{
    const Shape& shape1 = Drawing.getByName(name1); // Допустим, это Triangle
    const Shape& shape2 = Drawing.getByName(name2); // Допустим, это Circle
    return shape1.getIntersection(shape2);  // будет вызвана виртуальная функция Triangle::getIntersection, которая
    // в свою очередь вызовет у shape2 виртуальный метод Circle::getIntersectionT
}
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
31.03.2013, 13:12  [ТС]     Двойная диспетчеризация :) #4
Цитата Сообщение от Nick Alte Посмотреть сообщение
Есть хороший пример на графических примитивов в каком-нибудь векторном графическом редакторе. Допустим, есть общий предок Shape, от которого наследуются Circle, Square и Triangle (круг, квадрат, треугольник). Нам надо уметь определить площадь пересечения двух фигур. Очевидно, математика такого пересечения зависит от того, какие именно фигуры пересекаются. Но вот сам рисунок представлен в виде коллекции указателей на Shape, где мы можем выбрать произвольно два объекта и поинтересоваться площадью их пересечения. Вот тут-то и вступает в дело двойная диспетчеризация:
Да как раз эту задачу решаю.

Добавлено через 2 минуты
это называется полиморфизм.

Добавлено через 6 минут
У меня функция должна принимать два объекта типа Shape.

Добавлено через 43 секунды
И почему в производных классах от Shape функции виртуальные?
Nick Alte
Эксперт С++
1561 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,897
Завершенные тесты: 1
31.03.2013, 13:13     Двойная диспетчеризация :) #5
А давайте не будем разбрасываться терминами без их чёткого понимания. Виртуальные функции - штатное воплощение механизма динамического полиморфизма в C++. То, что я показал - реализация двойной диспетчеризации посредством этого механизма.
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
31.03.2013, 13:14  [ТС]     Двойная диспетчеризация :) #6
// Реализуем вычисление площади, зная тип нашей фигуры (круг) и второй фигуры
А вторая фигура это фигура имеется в веду объекта this?

Добавлено через 56 секунд
Nick Alte, Ок. Я еще подчитаю, а то я что такое виртуальная функция не сильно понимаю.
Nick Alte
Эксперт С++
1561 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,897
Завершенные тесты: 1
31.03.2013, 13:15     Двойная диспетчеризация :) #7
Цитата Сообщение от ninja2 Посмотреть сообщение
И почему в производных классах от Shape функции виртуальные?
Потому что виртуальные функции предка остаются таковыми и у потомка, в этом-то весь их смысл. Заметим, что у класса Shape этих функций вообще нет, есть только возможность их вызова в потомке. Они остались бы виртуальными даже без слова virtual, но с ним запись получается чётче и яснее.
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
31.03.2013, 13:31  [ТС]     Двойная диспетчеризация :) #8
Цитата Сообщение от Nick Alte Посмотреть сообщение
Потому что виртуальные функции предка остаются таковыми и у потомка, в этом-то весь их смысл. Заметим, что у класса Shape этих функций вообще нет, есть только возможность их вызова в потомке. Они остались бы виртуальными даже без слова virtual, но с ним запись получается чётче и яснее.
Помоему я где то читал, что виртуальные функции нужно переопределять, потому что они ничего не делают хз. или то чисто виртуальные функции? ,а обычные просто виртуальные функции это как бы флаг для производных классов, что их нужно переопределить. Запутался вообще.
(с определениями нада и правда разобраться)

Добавлено через 1 минуту
Щас протестирую можно ли для объекта класса с виртуальными функциями их вызвать.

Добавлено через 9 минут
Ладно тестить не будим просто вспомнил, что абстрактный класс это класс с чисто виртуальной функцией.
Чисто виртуальная функция это тупо пустая функция которую нужно переопределить в производном классе.
А просто виртуальная функция, это как обычная функция, токо с обязательным переопределением в производном классе. Вроде так.
Nick Alte
Эксперт С++
1561 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,897
Завершенные тесты: 1
31.03.2013, 13:31     Двойная диспетчеризация :) #9
Виртуальные функции вызываются "по факту", в зависимости от реального типа объекта. Отсюда и название (virtual переводится как "фактический"). Иллюстрация:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
using std::cout;
using std::endl;
 
class Base {
public:
    void foo() const {cout << "Base::foo" << endl;}
    virtual void bar() const {cout << "Base::bar" << endl;}
};
 
class Derived: public Base{
public:
    void foo() const {cout << "Derived::foo" << endl;}
    virtual void bar() const {cout << "Derived::bar" << endl;}
};
 
int main()
{
    Base b;
    Derived d;
    Base* pb = &d;
    b.foo();  // Печатает Base::foo
    b.bar();  // Печатает Base::bar
    d.foo();  // Печатает Derived::foo
    d.bar();  // Печатает Derived::bar
    pb->foo();    // Печатает Base::foo, хотя pb указывает на объект Derived, потому что pb имеет тип Base*
    pb->bar();    // Печатает Derived::bar, потому что функция виртуальная и вызывается через сам объект, который знает свой настоящий тип
}
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
31.03.2013, 13:34     Двойная диспетчеризация :) #10
ninja2,
Чисто виртуальная функция это тупо пустая функция которую нужно переопределить в производном классе.
Переопределить нужно, да. А вот что она тупо пустая - неверно.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
 
class Base
{
public:
   virtual ~Base() {}
   virtual void f() = 0;
};
 
void Base::f() { std::cout << "f" << std::endl; }
 
class Der : public Base
{
public:
   void f() { std::cout << "Der::f" << std::endl; Base::f(); }
};
 
int main()
{
   Base* b = new Der();
   b->f();
   delete b;
}
http://liveworkspace.org/code/3lblwO$0
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
31.03.2013, 13:34     Двойная диспетчеризация :) #11
Что-то как-то у вас всё сложно. Что такое двойная диспетчеризация поняли? Виртуальные функции — это реализация одинарной диспетчеризации. Принципиально она может быть сколько-угодно-арной.
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
31.03.2013, 14:15  [ТС]     Двойная диспетчеризация :) #12
Цитата Сообщение от Nick Alte Посмотреть сообщение
Виртуальные функции вызываются "по факту", в зависимости от реального типа объекта. Отсюда и название (virtual переводится как "фактический"). Иллюстрация:
Так можно просто в классе Derived bar записать без virtual
отак:
C++
1
2
3
4
5
class Derived: public Base{
public:
    void foo() const {cout << "Derived::foo" << endl;}
    void bar() const {cout << "Derived::bar" << endl;}
};
и в программке то же самое выводится:
C++
1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
    Base b;
    Derived d;
    Base* pb = &d;
    b.foo();  // Печатает Base::foo
    b.bar();  // Печатает Base::bar
    d.foo();  // Печатает Derived::foo
    d.bar();  // Печатает Derived::bar
    pb->foo();    // Печатает Base::foo, хотя pb указывает на объект Derived, потому что pb имеет тип Base*
    pb->bar();    // Печатает Derived::bar, потому что функция виртуальная и вызывается через сам объект, который знает свой настоящий тип
}
Он же наверно смотрит по базовой виртуальной функции. (компилятор смотрит)

Добавлено через 5 минут
Ладно понял для чоткой записи virtual оставляем.
Спасибо всем щас буду на практике пробовать как чо работает.

Добавлено через 4 минуты
Щас я напишу простую программку реализующую двойную диспетчеризацию на примере Shape и производных Triangle, Square, и Rectangle. Зацените правильно ли сделал.

Добавлено через 20 минут
От написал ну чото это похоже на одинарную диспетчеризацию, яж ведь как бы одну функцию вызвал, только два объекта как параметры передал или это и есть двойная диспетчеризация?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
using std::cout;
using std::endl;
 
class Shape
{
public:
    virtual void intersec(Shape a, Shape b){};//f opredel9yucha9 perecechenie
};
 
class Triangle : public Shape
{
public:
    virtual void intersec(Shape a, Shape b)
    {
        cout <<"intersec Triangle"<<endl;
    }
};
 
class Square : public Shape
{
public:
    virtual void intersec(Shape a, Shape b)
    {
        cout <<"intersec Square"<<endl;
    }
};
 
class Rectangle : public Shape
{
public:
    virtual void intersec(Shape a, Shape b)
    {
        cout <<"intersec Rectangle"<<endl;
    }
};
 
int main()
{
    Shape* Shape;
    Rectangle R;
    Triangle T;
    Square S;
    Shape=&R;
    Shape->intersec(R,T);//intersec Rectangle
    
    return 0;
}
Добавлено через 3 минуты
По условию задачи нужно два объекта передавать. Но я так смотрю можно б и один параметр хз. Второй же объект в самом классе как бы известен.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
31.03.2013, 18:00     Двойная диспетчеризация :)
Еще ссылки по теме:

C++ Двойная алгебраическая сумма (сигма)
Консольная двойная буферирзация C++
Указатели. Матрица и двойная косвенная адресация C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Nick Alte
Эксперт С++
1561 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,897
Завершенные тесты: 1
31.03.2013, 18:00     Двойная диспетчеризация :) #13
Передавать нужно по ссылке или по указателю, иначе создаётся копия объекта Shape, в которую заливают соответствующий кусок более крутого объекта. Чтобы избежать такой глупости, в Shape должны быть чистые виртуальные функции. Внимательно смотрим код моего примера.
Yandex
Объявления
31.03.2013, 18:00     Двойная диспетчеризация :)
Ответ Создать тему
Опции темы

Текущее время: 15:11. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru