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

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

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 35, средняя оценка - 4.71
Sanek911
4 / 4 / 0
Регистрация: 04.12.2009
Сообщений: 42
26.03.2012, 23:31     Как узнать, какого типа объект находится по указателю #1
Есть массив указателей базового класса, нужно узнать какие типы этих объектов.
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());
  }
//предложите код который поможет узнать типы объектов в векторе
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
26.03.2012, 23:31     Как узнать, какого типа объект находится по указателю
Посмотрите здесь:

C++ как удалить объект по указателю на базовый класс?
C++ не удаётся создать безымянный объект типа vector моего типа
интерфейс, в методе которого создается объект типа IDictionary и возвращается ссылка на этот объект C++
C++ объясните пожалуйста: tz какого типа
C++ Как записать объект с полем типа std::string в бинарном виде в файл и считать его обратно?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
26.03.2012, 23:34     Как узнать, какого типа объект находится по указателю #2
смотрите описание к оператору dynamic_cast. позволяет кастить указатель на базу к указателю на производный класс с проверкой. если производный имеет нужный тип, то скастится, иначе оператор вернет нуль или кинет исключение при преобразовании ссылок.
igorrr37
 Аватар для igorrr37
1593 / 1221 / 118
Регистрация: 21.12.2010
Сообщений: 1,868
Записей в блоге: 7
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;
}
Миниатюры
Как узнать, какого типа объект находится по указателю  
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
27.03.2012, 06:15     Как узнать, какого типа объект находится по указателю #4
Полиморфизм нужен для того, чтобы игнорировать действительный тип объектов и работать только с базовым.
dqrest
2 / 2 / 0
Регистрация: 06.01.2012
Сообщений: 114
12.11.2012, 10:01     Как узнать, какого типа объект находится по указателю #5
Если не хочешь разбираться с кастами и полиморфизмом, то заведи переменную в базовом классе флаг и с помощью него можешь узнавать тип уазателя
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
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.edu/lib...dt/glava12.pdf
http://gcc.gnu.org/onlinedocs/libstd...1pt12ch39.html
http://www.cplusplus.com/reference/s...nfo/type_info/
Определить все данные, тип которых вводится из командной строки
Определение введенного типа
Завернин
1 / 1 / 0
Регистрация: 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 или явное преобразование - это еще прирост скорости.
Voivoid
 Аватар для Voivoid
580 / 256 / 12
Регистрация: 31.03.2013
Сообщений: 1,284
23.01.2015, 21:41     Как узнать, какого типа объект находится по указателю #8
Цитата Сообщение от Завернин Посмотреть сообщение
не прибегая к преобразованию базовых элементов к родительским типам
Двойная диспетчеризация.

А dynamic_cast'ы и прочие "завести переменную" нужны только неосиляторам которые не могут спроектировать систему типов.
mishelle92
57 / 56 / 19
Регистрация: 09.10.2012
Сообщений: 179
Завершенные тесты: 1
23.01.2015, 23:53     Как узнать, какого типа объект находится по указателю #9
Цитата Сообщение от Voivoid Посмотреть сообщение
Двойная диспетчеризация.
Можно пример кода увидеть? Не пойму как это решит вопрос ТС-а.

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



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

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

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

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

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

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

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

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

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

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

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

Что-то подобное в оо-архитектуре красноречивый признак её ущербности.
Завернин
1 / 1 / 0
Регистрация: 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#).

А вот избавиться от динамической типизации вряд ли получится. Отказываться от абстрактной коллекции тоже смысла не вижу и не считаю это ущербным. В принципах ООП ничего нет про ущербность абстрактных коллекций=)
Voivoid
 Аватар для Voivoid
580 / 256 / 12
Регистрация: 31.03.2013
Сообщений: 1,284
20.02.2015, 23:35     Как узнать, какого типа объект находится по указателю #14
Цитата Сообщение от Завернин Посмотреть сообщение
Для двойной диспетчеризации нужно знать какого типа объекты взаимодействуют. Она также не будет работать с коллекцией объектов базового типа
Лолшто? Ты похоже вообще не шаришь о чем идет речь. На вот, просветись что-ли, довольно приятная реализация мультиметодов на плюсах: https://github.com/jll63/yomm11
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11841 / 6820 / 771
Регистрация: 27.09.2012
Сообщений: 16,911
Записей в блоге: 2
Завершенные тесты: 1
20.02.2015, 23:39     Как узнать, какого типа объект находится по указателю #15
Цитата Сообщение от Voivoid Посмотреть сообщение
На вот, просветись что-ли, довольно приятная реализация мультиметодов на плюсах
да у Александресску тоже нормально расписано. Можно сначала к его труду отослать
Завернин
1 / 1 / 0
Регистрация: 22.12.2013
Сообщений: 27
21.02.2015, 00:39     Как узнать, какого типа объект находится по указателю #16
Цитата Сообщение от Croessmah Посмотреть сообщение
да у Александресску тоже нормально расписано. Можно сначала к его труду отослать
Цитата Сообщение от Voivoid Посмотреть сообщение
довольно приятная реализация мультиметодов на плюсах: https://github.com/jll63/yomm11
Спасибо. Просвещусь на досуге. Как я понимаю, в обоих случаях реализация осуществляется с помощью шаблонов.
Возможно они и лучше по многим аспектам, я пока эти подходы не изучил.
Я ищу подход не только для плюсов, но и для C#. Там это скорее всего будет нереализуемо.
hoggy
5229 / 2120 / 404
Регистрация: 15.11.2014
Сообщений: 4,812
Завершенные тесты: 1
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);
}
Voivoid
 Аватар для Voivoid
580 / 256 / 12
Регистрация: 31.03.2013
Сообщений: 1,284
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 - будет ошибка компиляции
Завернин
1 / 1 / 0
Регистрация: 22.12.2013
Сообщений: 27
21.02.2015, 15:19     Как узнать, какого типа объект находится по указателю #19
Спасибо hoggy, мне очень понравилась такая реализация. Волшебный указатель this при вызове виртуального метода Intersect сам уже посылает нужный тип в функцию, действительно очень удобно, и работает также и на шарпе. Можно назвать это автоматическим приведением типа объекта посредством виртуальной функции. Небольшой минус в интерфейсе - нужно заводить две публичные функции для одного действия.
А вообще такой подход наверное применим во многих случаях в моих задачах.


Цитата Сообщение от Voivoid Посмотреть сообщение
Ну как вариант можно не городить велосипеды и заюзать boost::variant
Может и можно. Не пользовался бустом. Не рассмотрели важный момент, что нам еще важна последовательность элементов, и они должны храниться в коллекции. Полагаю, вряд ли можно сделать коллекцию из элементов variant<line, arc?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.02.2015, 15:57     Как узнать, какого типа объект находится по указателю
Еще ссылки по теме:

C++ Какого типа у нас *point ?
Как узнать, находится ли std::cout в hex-режиме? C++
Как передавать значения строкового типа в конструктор через объект класса? C++

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

Или воспользуйтесь поиском по форуму:
hoggy
5229 / 2120 / 404
Регистрация: 15.11.2014
Сообщений: 4,812
Завершенные тесты: 1
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); //<--- механизм времени компиляции распарсил аргументы
     // всех функций-обработчиков, которыми его накормили при создании
 
     //он знает какими теоретически могут быть аргументы
     //времени компиляции он проверяет входящие аргументы на предмет наследственных связей
 
    //фактически там, внутри его на шаблонах развернулась невидимая архитектура, 
    //очень сильно похожая на ту, что я приводил в предыдущем своем примере
 
    //вот только умный механизм сделал это самостоятельно, 
    //автоматически, без участия человека
 
    //от человека нужно только написать сами функции-обработчики
    //и указать их список мультиметоду.
    //все остальное он сделает сам.
 
}

зы: это лишь концепт-дизайн. Я ничего подобного ещё не делал.
Однако, мои знания шаблонов с++ дают мне основание полагать,
что подобный дизайн реален. Хотя работа не на один вечер.
Yandex
Объявления
21.02.2015, 15:57     Как узнать, какого типа объект находится по указателю
Ответ Создать тему
Опции темы

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