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

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

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

Студворк — интернет-сервис помощи студентам
Есть массив указателей базового класса, нужно узнать какие типы этих объектов.
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
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
26.03.2012, 23:31
Ответы с готовыми решениями:

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

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

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

22
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
26.03.2012, 23:34
смотрите описание к оператору dynamic_cast. позволяет кастить указатель на базу к указателю на производный класс с проверкой. если производный имеет нужный тип, то скастится, иначе оператор вернет нуль или кинет исключение при преобразовании ссылок.
1
 Аватар для igorrr37
2870 / 2017 / 991
Регистрация: 21.12.2010
Сообщений: 3,728
Записей в блоге: 15
27.03.2012, 01:50
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
Делаю внезапно и красиво
Эксперт С++
 Аватар для Deviaphan
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
27.03.2012, 06:15
Полиморфизм нужен для того, чтобы игнорировать действительный тип объектов и работать только с базовым.
0
4 / 4 / 0
Регистрация: 06.01.2012
Сообщений: 117
12.11.2012, 10:01
Если не хочешь разбираться с кастами и полиморфизмом, то заведи переменную в базовом классе флаг и с помощью него можешь узнавать тип уазателя
1
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,702
12.11.2012, 12:19
Тут нужна динамическая идентификация типов что-то такое:
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
Deviaphan, вы давно программируете? Категорически с Вами не согласен. Полиморфизм нужен как для использования общих виртуальных функций, так и для уникальных для каждого потомка. То есть это абсолютно рядовая задача программирования делать коллекцию базовых объектов и в дальнейшем преобразовывать их в потомки для дальнейшей обработки.
Вот один из множества примеров, взятых из реальной жизни: у Вас есть коллекция графических примитивов в виде линий и дуг, основанных на одном общем родительском классе gElement. Попробуйте написать функцию, находящую точки пересечения двух произвольных элементов, принимающую в качестве аргументов ссылки на gElement (double[] Intersection(gElement el1, gElement el2), не прибегая к преобразованию базовых элементов к родительским типам.

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

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

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



А ответ на вопрос ТС'а простой - не нужно знать типы этих объектов.
1
1 / 1 / 1
Регистрация: 22.12.2013
Сообщений: 27
20.02.2015, 16:20
Цитата Сообщение от Voivoid Посмотреть сообщение
Двойная диспетчеризация.
А dynamic_cast'ы и прочие "завести переменную" нужны только неосиляторам которые не могут спроектировать систему типов.
Для двойной диспетчеризации нужно знать какого типа объекты взаимодействуют. Она также не будет работать с коллекцией объектов базового типа. Если вы считаете такие коллекции бессмыленными - это ваш личный подход. Возможно вы предпочитаете писать на чистом С. С точки зрения ООП такие коллекции полностью оправданы и позволяют реализовать многие возможности ООП. Возможно вы неправильно понимаете идеологию ООП.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
20.02.2015, 16:57
Цитата Сообщение от Завернин Посмотреть сообщение
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
Цитата Сообщение от 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
 Аватар для Voivoid
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
20.02.2015, 23:35
Цитата Сообщение от Завернин Посмотреть сообщение
Для двойной диспетчеризации нужно знать какого типа объекты взаимодействуют. Она также не будет работать с коллекцией объектов базового типа
Лолшто? Ты похоже вообще не шаришь о чем идет речь. На вот, просветись что-ли, довольно приятная реализация мультиметодов на плюсах: https://github.com/jll63/yomm11
1
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
20.02.2015, 23:39
Цитата Сообщение от Voivoid Посмотреть сообщение
На вот, просветись что-ли, довольно приятная реализация мультиметодов на плюсах
да у Александресску тоже нормально расписано. Можно сначала к его труду отослать
1
1 / 1 / 1
Регистрация: 22.12.2013
Сообщений: 27
21.02.2015, 00:39
Цитата Сообщение от Croessmah Посмотреть сообщение
да у Александресску тоже нормально расписано. Можно сначала к его труду отослать
Цитата Сообщение от Voivoid Посмотреть сообщение
довольно приятная реализация мультиметодов на плюсах: https://github.com/jll63/yomm11
Спасибо. Просвещусь на досуге. Как я понимаю, в обоих случаях реализация осуществляется с помощью шаблонов.
Возможно они и лучше по многим аспектам, я пока эти подходы не изучил.
Я ищу подход не только для плюсов, но и для C#. Там это скорее всего будет нереализуемо.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
21.02.2015, 01:03
Цитата Сообщение от Завернин Посмотреть сообщение
Лучше рассмотреть на конкретной задаче:
Есть 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
 Аватар для Voivoid
710 / 283 / 16
Регистрация: 31.03.2013
Сообщений: 1,340
21.02.2015, 01:26
Ну как вариант можно не городить велосипеды и заюзать 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
Спасибо hoggy, мне очень понравилась такая реализация. Волшебный указатель this при вызове виртуального метода Intersect сам уже посылает нужный тип в функцию, действительно очень удобно, и работает также и на шарпе. Можно назвать это автоматическим приведением типа объекта посредством виртуальной функции. Небольшой минус в интерфейсе - нужно заводить две публичные функции для одного действия.
А вообще такой подход наверное применим во многих случаях в моих задачах.


Цитата Сообщение от Voivoid Посмотреть сообщение
Ну как вариант можно не городить велосипеды и заюзать boost::variant
Может и можно. Не пользовался бустом. Не рассмотрели важный момент, что нам еще важна последовательность элементов, и они должны храниться в коллекции. Полагаю, вряд ли можно сделать коллекцию из элементов variant<line, arc?
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
21.02.2015, 15:57
Цитата Сообщение от Завернин Посмотреть сообщение
Полагаю, вряд ли можно сделать коллекцию из элементов 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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
21.02.2015, 15:57
Помогаю со студенческими работами здесь

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru