Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.81/106: Рейтинг темы: голосов - 106, средняя оценка - 4.81
7 / 7 / 1
Регистрация: 04.12.2009
Сообщений: 42
1

Как узнать, какого типа объект находится по указателю

26.03.2012, 23:31. Показов 22092. Ответов 22
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Есть массив указателей базового класса, нужно узнать какие типы этих объектов.
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
class Shape{
public:
  ~Shape(){}
  virtual void Draw() = 0;
};
class Triangle : public Shape{
  virtual void Draw(){}
};
class Circle : public Shape{
  virtual void Draw(){}
};
class Square : public Shape{
  virtual void Draw(){}
};
 
void main()
{
  std::vector<Shape *> vec;
  for(int i = 0; i < 10; i++){
    if ((i % 3) == 0)
      vec.push_back(new Triangle());
    if ((i % 3) == 1)
      vec.push_back(new Circle()); 
    if ((i % 3) == 2)
      vec.push_back(new Square());
  }
//предложите код который поможет узнать типы объектов в векторе
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
26.03.2012, 23:31
Ответы с готовыми решениями:

Как определиться объект какого типа мы перетаскивали мышью?
Всем здравствуйте. На форме label1 и button1. Оба объекта могут инициировать перетаскивание по...

Как узнать находится ли объект в фокусе
Создаю компонент. Как мне внутри компонента понять, что он находится в фокусе? if focused=true не...

Как узнать что находится в переменной типа byte[]
Здравствуйте. Я имею простенький чат p2p. При передаче текста, я его перевожу из string в byte, ну...

Forbids casting в dlsym - ISO C++ не поддерживает приведение типа указателя на функцию к указателю на объект
Есть вот такой пример загрузки .so #include &lt;iostream&gt; #include &lt;dlfcn.h&gt; int main() { ...

22
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
26.03.2012, 23:34 2
смотрите описание к оператору dynamic_cast. позволяет кастить указатель на базу к указателю на производный класс с проверкой. если производный имеет нужный тип, то скастится, иначе оператор вернет нуль или кинет исключение при преобразовании ссылок.
1
2848 / 1997 / 986
Регистрация: 21.12.2010
Сообщений: 3,705
Записей в блоге: 10
27.03.2012, 01:50 3
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
#include <iostream>
#include <vector>
#include <typeinfo>
 
class Shape
{
public:
    ~Shape(){}
    virtual void Draw() = 0;
};
 
class Triangle : public Shape
{
public:
    virtual void Draw(){}
};
 
class Circle : public Shape
{
public:
    virtual void Draw(){}
};
 
class Square : public Shape
{
public:
    virtual void Draw(){}
};
 
int main()
{
    std::vector<Shape*> vec;
    for(int i = 0; i < 10; i++)
    {
        if ((i % 3) == 0) vec.push_back(new Triangle());
        if ((i % 3) == 1) vec.push_back(new Circle());
        if ((i % 3) == 2) vec.push_back(new Square());
    }
    for(auto p : vec)
    {
        std::cout << typeid(*p).name() << std::endl;
    }
    return 0;
}
Миниатюры
Как узнать, какого типа объект находится по указателю  
3
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
27.03.2012, 06:15 4
Полиморфизм нужен для того, чтобы игнорировать действительный тип объектов и работать только с базовым.
0
4 / 4 / 0
Регистрация: 06.01.2012
Сообщений: 117
12.11.2012, 10:01 5
Если не хочешь разбираться с кастами и полиморфизмом, то заведи переменную в базовом классе флаг и с помощью него можешь узнавать тип уазателя
1
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
12.11.2012, 12:19 6
Тут нужна динамическая идентификация типов что-то такое:
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
49
50
51
52
#include <cxxabi.h>
#include <stdio.h>
#include <vector>
using namespace std;
 
class Shape{
public:
  ~Shape(){}
  virtual void Draw() = 0;
};
class Triangle : public Shape{
  virtual void Draw(){}
};
class Circle : public Shape{
  virtual void Draw(){}
};
class Square : public Shape{
  virtual void Draw(){}
};
 
int main()
{
  std::vector<Shape *> vec;
  for(int i = 0; i < 10; i++){
    if ((i % 3) == 0)
      vec.push_back(new Triangle());
    if ((i % 3) == 1)
      vec.push_back(new Circle()); 
    if ((i % 3) == 2)
      vec.push_back(new Square());
  }
 
 //собсно идентификация: 
 
 int status;
 char* realname;
 
 realname = abi::__cxa_demangle(typeid(*vec[0]).name(), 0, 0, &status);
 printf (realname);
 getchar ();
 
 realname = abi::__cxa_demangle(typeid(*vec[1]).name(), 0, 0, &status);
 printf (realname);
 getchar ();
 
 realname = abi::__cxa_demangle(typeid(*vec[2]).name(), 0, 0, &status);
 printf (realname);
 getchar ();
 
 
 
}

Дополнительно смотреть:
http://khpi-iip.mipk.kharkiv.e... lava12.pdf
http://gcc.gnu.org/onlinedocs/... 2ch39.html
http://www.cplusplus.com/refer... type_info/
Определить все данные, тип которых вводится из командной строки
Определение введенного типа
0
1 / 1 / 1
Регистрация: 22.12.2013
Сообщений: 27
23.01.2015, 19:44 7
Deviaphan, вы давно программируете? Категорически с Вами не согласен. Полиморфизм нужен как для использования общих виртуальных функций, так и для уникальных для каждого потомка. То есть это абсолютно рядовая задача программирования делать коллекцию базовых объектов и в дальнейшем преобразовывать их в потомки для дальнейшей обработки.
Вот один из множества примеров, взятых из реальной жизни: у Вас есть коллекция графических примитивов в виде линий и дуг, основанных на одном общем родительском классе gElement. Попробуйте написать функцию, находящую точки пересечения двух произвольных элементов, принимающую в качестве аргументов ссылки на gElement (double[] Intersection(gElement el1, gElement el2), не прибегая к преобразованию базовых элементов к родительским типам.

Добавлено через 23 минуты
А по топику полностью согласен с DU - нужно использовать dinamic_cast.
Ответ dqrest тоже хорош, можно завести переменную, перечисляющую родительские типы и указывающую явно в какой тип надо преобразовать, что увеличит скорость выполнения при увеличении количества наследников. В этом случае можно будет использовать static_cast или явное преобразование - это еще прирост скорости.
0
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
23.01.2015, 21:41 8
Цитата Сообщение от Завернин Посмотреть сообщение
не прибегая к преобразованию базовых элементов к родительским типам
Двойная диспетчеризация.

А dynamic_cast'ы и прочие "завести переменную" нужны только неосиляторам которые не могут спроектировать систему типов.
0
73 / 69 / 38
Регистрация: 09.10.2012
Сообщений: 238
23.01.2015, 23:53 9
Цитата Сообщение от Voivoid Посмотреть сообщение
Двойная диспетчеризация.
Можно пример кода увидеть? Не пойму как это решит вопрос ТС-а.

Или имелось в виду, что решать задачу "Есть массив указателей базового класса, нужно узнать какие типы этих объектов." саму по себе не имеет смысла?
0
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
24.01.2015, 14:09 10
Цитата Сообщение от mishelle92 Посмотреть сообщение
Можно пример кода увидеть? Не пойму как это решит вопрос ТС-а.
Вопрос ТС'а это никак не решит. Я неудачно процитировал, это ответ на вопрос:
Цитата Сообщение от Завернин Посмотреть сообщение
Попробуйте написать функцию, находящую точки пересечения двух произвольных элементов



А ответ на вопрос ТС'а простой - не нужно знать типы этих объектов.
1
1 / 1 / 1
Регистрация: 22.12.2013
Сообщений: 27
20.02.2015, 16:20 11
Цитата Сообщение от Voivoid Посмотреть сообщение
Двойная диспетчеризация.
А dynamic_cast'ы и прочие "завести переменную" нужны только неосиляторам которые не могут спроектировать систему типов.
Для двойной диспетчеризации нужно знать какого типа объекты взаимодействуют. Она также не будет работать с коллекцией объектов базового типа. Если вы считаете такие коллекции бессмыленными - это ваш личный подход. Возможно вы предпочитаете писать на чистом С. С точки зрения ООП такие коллекции полностью оправданы и позволяют реализовать многие возможности ООП. Возможно вы неправильно понимаете идеологию ООП.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
20.02.2015, 16:57 12
Цитата Сообщение от Завернин Посмотреть сообщение
Deviaphan, вы давно программируете?
Учитывая, что последняя запись от господина kravam датирована 2012 годом, то как минимум 3 года.

А учитывая общую подкованность господина Deviaphan,
то можно смело предположить, что он и в 2012 уже был специалистом.
---------------------------------------------------------------

Цитата Сообщение от Завернин Посмотреть сообщение
Возможно вы предпочитаете писать на чистом С. С точки зрения ООП такие коллекции полностью оправданы и позволяют реализовать многие возможности ООП. Возможно вы неправильно понимаете идеологию ООП.
А вот ваши ответы красноречиво намекают: вы не умеете ооп.

1. Язык си, со своей процедурной парадигмой не имеет никакого отношения к ответа господина Deviaphan.

2. Технология полиморфизм, на которой базируется оо-парадигма,
была разработана, что бы реализовать идеому: "закрыт для изменений, открыт для расширений".

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

3. То, как вы предлагаете использовать полиморфизм на корню прибивает идеому,
ради которой он и был создан. И прекрасно реализуется на тех же свитч-кейсах (имея при этом все их недостатки).

Это дает основание предположить, что вы сами не понимаете ООП.

Более того: именно к вам можно обратить ваш собственный тезис:

С точки зрения ООП ваш юзкейс нарушает идеому "зарыт для изменений, открыт для расширений",
и прекрасно реализуется на обычном процедурном си при помощи свит-кейсов,
или конструкций из if/else, имея при этом все их недостатки.

Возможно вы предпочитаете писать на чистом С.
Возможно вы просто неправильно понимаете идеологию ООП.
Но такие коллекции не оправданы с точки зрения ООП,
и ломают на корню многие из его возможностей.

Что-то подобное в оо-архитектуре красноречивый признак её ущербности.
1
1 / 1 / 1
Регистрация: 22.12.2013
Сообщений: 27
20.02.2015, 21:47 13
Цитата Сообщение от hoggy Посмотреть сообщение
Более того: именно к вам можно обратить ваш собственный тезис:
С точки зрения ООП ваш юзкейс нарушает идеому "зарыт для изменений, открыт для расширений",
Согласен, принцип открытости-закрытости может нарушаться в абстрактных коллекциях.
С теоретической точки зрения да, если нам нужна динамическая типизация, то мы не соблюдаем этот принцип.

Но программирование прежде всего имеет смысл с точки зрения практики.
И не спроста язык предлагает нам инструменты динамической типизации вроде dinamic_cast и typeid.
Можно обойтись и без таких коллекций, только это усложнит реализацию.

Лучше рассмотреть на конкретной задаче:
Есть 2 контура Contour, состоящих из последовательно соединенных линий Line: Element и дуг Arc: Element.
Нам нужно найти точки пересечения этих контуров.

Архитектурное решение с применением абстрактных коллекций: Перечисляем элементы первого контура, для каждого из них перечисляем все элементы второго контура и вызываем у них метод PointF pf = el1.Intersect(el2);
В методе Intersect каждого типа пишем свич-кейсы. Нарушаем принцип открытости-закрытости (при добавлении новых типов примитивов придется дописывать свич-кейсы в каждом "братском" классе), но простота реализации и поддержки, а также скорость выполнения программы при большом количестве элементов (касты делаются быстро, по крайней мере на C#).

Какую можете предложить альтернативу? (Естественно в приватных функциях контура должны сохраняться возможности вставки, удаления, инверсии элементов, и желательно доступа к элементу по индексу).

Добавлено через 39 минут
Архитектурное решение с применением абстрактных коллекций: Вызываем метод cont1.Intersect(cont2); Перечисляем элементы первого контура, приводим к производному типу. Для каждого из них перечисляем все элементы второго контура, приводим их и вызываем метод PointF pf = (line1/arc1).Intersect(line2/arc2);
Все свич-кейсы пишутся в методе Contour.Intersect. При добавлении новых типов примитивов, нужно будет дописать свич кейсы только этого метода, а ранее написанный код примитивов останется без изменений.
В такой реализации не нарушается принцип открытости-закрытости, но остается простота реализации и поддержки, а также скорость выполнения программы при большом количестве элементов (касты делаются быстро, по крайней мере на C#).

А вот избавиться от динамической типизации вряд ли получится. Отказываться от абстрактной коллекции тоже смысла не вижу и не считаю это ущербным. В принципах ООП ничего нет про ущербность абстрактных коллекций=)
0
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
20.02.2015, 23:35 14
Цитата Сообщение от Завернин Посмотреть сообщение
Для двойной диспетчеризации нужно знать какого типа объекты взаимодействуют. Она также не будет работать с коллекцией объектов базового типа
Лолшто? Ты похоже вообще не шаришь о чем идет речь. На вот, просветись что-ли, довольно приятная реализация мультиметодов на плюсах: https://github.com/jll63/yomm11
1
Неэпический
17869 / 10634 / 2054
Регистрация: 27.09.2012
Сообщений: 26,736
Записей в блоге: 1
20.02.2015, 23:39 15
Цитата Сообщение от Voivoid Посмотреть сообщение
На вот, просветись что-ли, довольно приятная реализация мультиметодов на плюсах
да у Александресску тоже нормально расписано. Можно сначала к его труду отослать
1
1 / 1 / 1
Регистрация: 22.12.2013
Сообщений: 27
21.02.2015, 00:39 16
Цитата Сообщение от Croessmah Посмотреть сообщение
да у Александресску тоже нормально расписано. Можно сначала к его труду отослать
Цитата Сообщение от Voivoid Посмотреть сообщение
довольно приятная реализация мультиметодов на плюсах: https://github.com/jll63/yomm11
Спасибо. Просвещусь на досуге. Как я понимаю, в обоих случаях реализация осуществляется с помощью шаблонов.
Возможно они и лучше по многим аспектам, я пока эти подходы не изучил.
Я ищу подход не только для плюсов, но и для C#. Там это скорее всего будет нереализуемо.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
21.02.2015, 01:03 17
Цитата Сообщение от Завернин Посмотреть сообщение
Лучше рассмотреть на конкретной задаче:
Есть 2 контура Contour, состоящих из последовательно соединенных линий Line: Element и дуг Arc: Element.
Нам нужно найти точки пересечения этих контуров.
Пускай для простоты будет не линия, а отрезок.

Нужно отталкиваться от "способа обобщения".

Что у нас есть?
Контур, который может состоять из линий, дуг, и может быть ещё чего нибудь придумаем.

Что общего у отрезков и дуг?

Если мы можем выделить общее у этих двух элементов, например:
"отрезок - это примитив состоящий из 2х точек"
"дуга - это примитив состоящий из И отрезков"

Пойдем дальше в нашем обобщении:
отрезок - это контейнер для двух точек

Но если так,
то совокупность отрезков можно представить в виде списка точек.

А значит дуга - это контейнер из И точек.
И по аналогии, контур - это так же контейнер из N точек.

Итого: вся архитектура сводится всего к двум элементам: точка, и контейнер точек.

Дуги, отрезки, квадраты, прямоугольники и прочее - это все опционально.
Всего лишь методы "удобного и быстрого" построения типичных фигур:

C++
1
2
3
4
5
6
7
8
//получили дугу из N точек
auto arc = Figure::create<Arc>(param1);
 
//получили отрезок
auto line = Figure::create<Line>(param2);
 
//получили замкнутую фигуру из одной дуги и одного отрезка
auto fugure = (arc + line).close();
Очевидно, что при таком обобщении достаточно одного единственного алгоритма
поиска пересечений для фигур состоящих из И точек.


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

---------------------------------------------------------------------------------------------

Теперь предположим, что в силу специфики задачи мы не можем прибегнуть к адаптивной деградации
Предположим, нам нужно делать весьма точные расчеты,
и оперировать нужно именно окружностями и настоящими дугами, а вовсе не многоугольниками.
(предположим, что так захотел заказчик, и баста! )

В этом случае становится очевидным,
что сделать универсальный алгоритм пересечения не получится.

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

Требование к задаче "выполнять обработку по уникальным способом в зависимости от типов участников",
уже противоречит идее полиморфизма.

И с этим мы бессильны, что либо поделать.
Мы можем лишь облегчить сопровождение такого подхода.

Например, мы можем построить решение,
которое частично может поспособствовать универсальности решения.

Допустим, если линия не умеет пересекаться с окружностью
(программисты ещё не успели доделать этот алгоритм,
но уже сейчас нужно показать промежуточные результаты работы),
то линия может попросить окружность "адаптивно деградироваться",
и в итоге отработает универсальный алгоритм.

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

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

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

Ниже представленный код - пример-иллюстрация одного из возможных решений:

http://rextester.com/JAIUXZ12714

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <string>
#include <typeinfo>
#include <iostream>
using namespace std;
 
struct Circle;
struct Line;
struct Arc;
 
struct Element
{
    virtual void Intersect(Element& Object) = 0;
 
    virtual void Collision(Element&) = 0;
    
    //--- элементы не обязаны уметь обрабатывать данный тип фигуры
    // если они не определили алгоритм обработки - 
    // будет задействован универсальный алгоритм с применением адаптивной деградации
    virtual void Collision(Circle& el);
 
    virtual void Collision(Line&) = 0;
    virtual void Collision(Arc&) = 0;
 
    static void Collision(Line&, Line&)
        { cout << "intersection: line vs line\n";     }
    static void Collision(Line&, Arc&)
        {  cout << "intersection: line vs arc\n";     }
    static void Collision(Arc&, Arc&)
        { cout << "intersection: arc vs arc\n";       }
    static void Collision(Circle&, Circle&)
        { cout << "intersection: circle vs circle\n"; }
 
    template<class T>
    static void Collision(Circle&, T&)
        { cout << "circle vs figure with adaptive degradation...\n"; }
 
    
 
    
};
 
struct Line : Element
{
    //--- если срабатывает метод, принимающий базовый элемент
    // значит данная фигура не знает уникального алгоритма обработки
    // фактического типа этого элемента
    // в этом случае задействуется универсальный алгоритм 
    // с использованием адаптивной деградации
    virtual void Collision(Element&)
        { cout << "line vs figure with adaptive degradation...\n";  }
 
    virtual void Collision(Line& l)
        { Element::Collision(*this, l); }
    virtual void Collision(Arc& a)
        { Element::Collision(*this, a); }
    virtual void Intersect(Element& object)
        { object.Collision(*this); }
};
 
struct Arc : Element
{
    virtual void Collision(Element&)
        { cout << "arc vs figure with adaptive degradation...\n"; }
 
    virtual void Collision(Line& l)
        { Element::Collision(l, *this); }
    virtual void Collision(Arc& a)
        { Element::Collision(*this, a); }
    virtual void Intersect(Element& object)
        { object.Collision(*this); }
};
 
struct Circle : Element
{
    virtual void Collision(Element&)
        { cout << "circle vs figure with adaptive degradation...\n"; }
 
    virtual void Collision(Line& l)
        { Element::Collision(*this, l); }
    virtual void Collision(Arc& a)
        { Element::Collision(*this, a); }
    virtual void Collision(Circle& c)
        { Element::Collision(*this, c); }
    virtual void Intersect(Element& object)
        { object.Collision(*this); }
};
 
 
void Element::Collision(Circle& el)
{
    Collision(static_cast<Element&>(el));
}
 
int main()
{
    Line   line;
    Arc    arc;
    Circle cir;
 
    line.Intersect(line);
    line.Intersect(arc);
    arc.Intersect(arc);
    arc.Intersect(line);
 
    cout << "--------------------------\n";
 
    cir.Intersect(line);
    cir.Intersect(arc);
    cir.Intersect(cir);
}
2
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
21.02.2015, 01:26 18
Ну как вариант можно не городить велосипеды и заюзать boost::variant

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
#include <boost/variant.hpp>
#include <stdexcept>
 
struct line {
 
};
 
struct arc {
 
};
 
struct intersects_algo : boost::static_visitor<bool> {
    bool operator()( const line& l1, const line& l2 ) const {
        throw std::runtime_error( "not implemented" );
    }
 
    bool operator()( const arc& a1, const arc& a2 ) const {
        throw std::runtime_error( "not implemented" );
    }
 
    bool operator()( const line& l, const arc& a ) const {
        throw std::runtime_error( "not implemented" );
    }
 
    bool operator()( const arc& a, const line& l ) const {
        return this->operator()( l, a );
    }
};
 
using element = boost::variant<line, arc>;
 
bool intersects( const element& e1, const element& e2 ) {
    return boost::apply_visitor(intersects_algo(), e1, e2 );
}
 
 
 
int main() {
 
    element e1 = line{};
    element e2 = arc{};
 
    bool result = intersects( e1, e2 );
 
    return 0;
}
В качестве бонуса - compile time чек наличия обработчиков. Т.е. если добавить в variant новый тип, но при этом не обновать visitor - будет ошибка компиляции
2
1 / 1 / 1
Регистрация: 22.12.2013
Сообщений: 27
21.02.2015, 15:19 19
Спасибо hoggy, мне очень понравилась такая реализация. Волшебный указатель this при вызове виртуального метода Intersect сам уже посылает нужный тип в функцию, действительно очень удобно, и работает также и на шарпе. Можно назвать это автоматическим приведением типа объекта посредством виртуальной функции. Небольшой минус в интерфейсе - нужно заводить две публичные функции для одного действия.
А вообще такой подход наверное применим во многих случаях в моих задачах.


Цитата Сообщение от Voivoid Посмотреть сообщение
Ну как вариант можно не городить велосипеды и заюзать boost::variant
Может и можно. Не пользовался бустом. Не рассмотрели важный момент, что нам еще важна последовательность элементов, и они должны храниться в коллекции. Полагаю, вряд ли можно сделать коллекцию из элементов variant<line, arc?
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
21.02.2015, 15:57 20
Цитата Сообщение от Завернин Посмотреть сообщение
Полагаю, вряд ли можно сделать коллекцию из элементов variant<line, arc?
Напрасно.

Добавлено через 33 минуты
Цитата Сообщение от Завернин Посмотреть сообщение
действительно очень удобно, и работает также и на шарпе.
Думаю, применив шаблонную магию, технически возможно реализовать фильдеперстовый мультиметод,
который выполняя проверки времени компиляции позволит разрулить динамику без необходимости обязательно от чего то там наследоваться, и реализовывать какие то методы.

Дизайн например мог бы выглядеть так:

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//участники 
struct Line: Element {...};
struct Arc: Element {...};
struct Circle: Element {...};
 
...
 
bool Collision(int, Arc&);      //<--- мультиметоду не важны наследственные связи
bool Collision(Some, Arc&);  // участники вообще не обязаны быть полиморфами
 
bool Collision(Line&, Arc&);
 
bool Collision(Arc&, Element&);  //<--- версия с базовым классом будет выбрана автоматически, 
//если нет обработчика, способного принять вторым аргументом фактический тип
 
bool CollisionEx(Element&, Element&); //<--- Можно использовать любые имена, а не только перегрузки
//версия, которая принимает оба аргумента в виде базовых классов
//выбирается, если не было обнаружено ни одного подходящего обработчика, 
//принимающего фактические типы
 
...
 
 
//где то в бизнес-коде функция, которая получает на вход базовые интерфейсы
//и ей нужно выполнить "пересечение"
 
boo Work(Element& one, Element& two )
{
     // здесь мы уже не владеем информацией о фактических типах элементов
     // но нам очень нужно выполнить пересечение
     // для этого мы создаем мультиметод
 
     // утилита make умеет создавать мультиметоды
     auto mmethod = tools::make<multimethod>(
 
         //от пользователя требуется просто перечислить функции-обработчики
 
         // утилита make помогает разрулить коллизии перегрузок
         tools::make<int, Arc&>(Collision),   
         tools::make<Some, Arc&>(Collision),
         tools::make<Line&, Arc&>(Collision),
         tools::make<Arc&, Element&>(Collision),
         CollisionEx //<--- уникальное имя можно закинуть без всяких утилит
     );
 
     return mmetod(one,two); //<--- механизм времени компиляции распарсил аргументы
     // всех функций-обработчиков, которыми его накормили при создании
 
     //он знает какими теоретически могут быть аргументы
     //времени компиляции он проверяет входящие аргументы на предмет наследственных связей
 
    //фактически там, внутри его на шаблонах развернулась невидимая архитектура, 
    //очень сильно похожая на ту, что я приводил в предыдущем своем примере
 
    //вот только умный механизм сделал это самостоятельно, 
    //автоматически, без участия человека
 
    //от человека нужно только написать сами функции-обработчики
    //и указать их список мультиметоду.
    //все остальное он сделает сам.
 
}

зы: это лишь концепт-дизайн. Я ничего подобного ещё не делал.
Однако, мои знания шаблонов с++ дают мне основание полагать,
что подобный дизайн реален. Хотя работа не на один вечер.
0
21.02.2015, 15:57
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.02.2015, 15:57
Помогаю со студенческими работами здесь

Как узнать из какого окна и какого процесса пришло сообщение?
Собственно один многооконный процесс посылает SendMessage другому процессу в какое - то окно. Можно...

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

От какого типа каждый объект прямо или косвенно является производным в .Net?
1 System.Object 2 System.Exception 3 Enumerator 4 System.Type

Можно ли узнать если объект находится на объекте?
Даны два объекта, один это Столб, а второй это мяч. Мячик летает по карте, как сделать когда мячик...

Как вернуть объект по указателю
У меня есть функция QStandardItemModel set_model(QStandardItemModel*a) { return a; } ...

Как удалить объект класс из кучи по указателю?
Как удалить экземпляр класса из кучи по указателю? Есть простенький код: запускает два потока,...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru