Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Ада и другие языки _ Автоматическое приведение типа указателя

Автор: Tony 9.08.2010 23:47

Доброго всем времени суток.

Имеется такой код:

class CBase
{
public:
virtual void MyVoid()=0;
};

class CDerv1 : public CBase
{
...
};

class CDerv2 : public CBase
{
...
};

...


т.е. есть некий базовый абстрактный класс, у которого много наследников.

Далее происходит вот что:
CBase *pBase = new CDerv1;


Вопрос : очевидно, например с помощью typeid мы можем узнать тип объекта, на который на самом деле указывает pBase. Существует ли простой способ автоматически преобразовать pBase из типа CBase* в тип того объекта, на который он на самом деле указывает (в данном случае в CDerv1*)?



Автор: volvo 10.08.2010 1:05

Цитата
Существует ли простой способ автоматически преобразовать pBase из типа CBase* в тип того объекта, на который он на самом деле указывает (в данном случае в CDerv1*)?
Интересно, каким образом ты представляешь подобное преобразование? То есть, тебе надо на этапе компиляции завести переменную, которая была бы соответствующего типа, чтоб туда записать преобразованный Base->Derived указатель? Или в каком виде тебе это нужно, уточни...

Автор: Tony 10.08.2010 18:37

Да, извиняюсь, что не уточнил. Есть некая перегруженная функция F, которая будет обрабатывать различные типы указателей(т.е. CDerv1*, CDerv2* и т.п).

P.S.
Я понимаю, конечно, что можно написать как-то так:

if ( typeid(*pBase).name() == "CDerv1" ) F( (CDerv1*)pBase );
if ( typeid(*pBase).name() == "CDerv2" ) F( (CDerv2*)pBase );
...


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

Автор: volvo 10.08.2010 19:23

Почему не написать полиморфную функцию:

void f(CBase *p)
{
p->myF(); // Виртуальная функция myF, и пусть класс сам разбирается, что ему надо делать
}


? Зачем ты уходишь от механизма виртуальных функций, и хочешь делать это же вручную? Можно, кстати,
Цитата
if ( typeid(*pBase).name() == "CDerv1" ) F( (CDerv1*)pBase );
if ( typeid(*pBase).name() == "CDerv2" ) F( (CDerv2*)pBase );

заменить на
    if(dynamic_cast<CDerv1*>(pBase)) f(dynamic_cast<CDerv1*>(pBase));
if(dynamic_cast<CDerv2*>(pBase)) f(dynamic_cast<CDerv2*>(pBase));

, но хрен редьки не слаще...

Хм... Ан нет, слаще. Под GCC твой вариант не работает (там строка в другом формате возвращается), а мой - работает. Или вот этот:
    if ( typeid(*pBase) == typeid(CDerv1)) f( (CDerv1*)pBase );
if ( typeid(*pBase) == typeid(CDerv2)) f( (CDerv2*)pBase );

, тоже работает.

Но основной вопрос был озвучен выше, почему не виртуальные функции?

Автор: Tony 10.08.2010 20:22

Да, ваш вопрос логичен. Но это видимо из-за того, что я слишком все упростил)

На самом деле функция f принимает два указателя (т.е. к примеру f(CDerv1*, CDerv2*)), т.е. она реализует попарное взаимодействие между объектами. Просто в данном случае получается так, что нельзя вытащить нужные данные объекта с помощью виртуальных функций(эти свойства слишком разные), а нужен просто сам объект; но опять-таки нельзя уйти и от виртуальных функций, так как без них все бы сильно усложнилось.

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

Автор: volvo 11.08.2010 1:14

А... Ты, значит, мультиметоды реализуешь? smile.gif Тогда тебе прямая дорога к книге А. Александреску "Современное проектирование на С++", 11 глава - "Мультиметоды", начиная со стр 281. Там найдешь много интересного для себя.

Или С. Майерс, "Наиболее эффективное использование С++" - правило №31: "Создавайте функции, виртуальные по отношению более чем к одному объекту"

Автор: Tony 11.08.2010 5:15

Да, volvo, огромное спасибо. Это как раз то, что мне было нужно) Жаль только, что в C++ их пока нет.