powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Downcasting. Вроде так это называется...
11 сообщений из 11, страница 1 из 1
Downcasting. Вроде так это называется...
    #33685123
Landanan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сразу к делу:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
class Base { public: int x,y; };
class Derived : public Base { public: int z; };
class AnotherDerived : public Base { public: int d; };

int main()
{
   Base *ptr = new Derived;

   cout << ptr->x << " " << ptr->y << " " << ptr->z;
   return  0 ;
}

Вот.
Эта программа не скомпилируется - меня будут ругать, что z is not a member of class Base.

Оно и понятно, потому как пойнтер типа Base.
Слышал про такую штуку, Downcasting называется...ну, это чтобы пойнтер типа Derived мог указывать на Base...

Задача у меня такая:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
int main()
{
   Base **list=new Base*[ 2 ];
   list[ 0 ] = new Derived;
   list [ 1 ] = new AnotherDerived;

   cout << list[ 0 ]->z << " " << list[ 1 ]->d;

   return  0 ;
}

Нужно чтобы это работало...
...
Рейтинг: 0 / 0
Downcasting. Вроде так это называется...
    #33685415
redskin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Landanan
Нужно чтобы это работало...


Так нельзя. Полиморфно можно работать только с виртуальными функциями. С невиртуальными функциями и членами данными - нет.
Т.е. можно конечно попробовать написать:

Код: plaintext
1.
 dynamic_cast<Derived*>(list[ 0 ])->z

или

Код: plaintext
1.
 ((Derived*)(list[ 0 ]))->z

и даже может быть будет работать, но лучше так не делать, а пересмотреть дизайн, чтобы в таком приведении типов не возникало необходимости
...
Рейтинг: 0 / 0
Downcasting. Вроде так это называется...
    #33685423
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
redskin
Так нельзя. Полиморфно можно работать только с виртуальными функциями. С невиртуальными функциями и членами данными - нет.


Почему нельзя ? Можно, только вопрос -- зачем ?
...
Рейтинг: 0 / 0
Downcasting. Вроде так это называется...
    #33685461
redskin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZiv redskin
Так нельзя. Полиморфно можно работать только с виртуальными функциями. С невиртуальными функциями и членами данными - нет.


Почему нельзя ? Можно, только вопрос -- зачем ?

"Можно" то "можно", но как оно будет работать?

Напишет автор что-нть вроде этого:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
struct Base
{
    virtual void f() {cout << "hi from Base\n";};
};

struct Deriv : public Base
{
    int n_member;
    virtual void f() {cout << "hi from Deriv\n";};
};

Потом вот это:

Код: plaintext
1.
2.
3.
4.
    Base* pd = new(Deriv);
    pd->f();
    dynamic_cast<Deriv*>(pd)->n_member =  1 ;
    cout << "test 1 ok\n";

И оно скомпилится и заработает.

А потом (случайно, нарочно, забудет, не поймет, еще что-нибудь) вот это:

Код: plaintext
1.
2.
3.
4.
    Base* pb = new(Base);
    pb->f();
    dynamic_cast<Deriv*>(pb)->n_member =  1 ;
    cout << "test 2 ok\n";


И оно тоже скомпилится, но запустив получим Segmentation fault в лучшем случае. IMHO лучше сразу привыкать к хорошему и не писать так.
...
Рейтинг: 0 / 0
Downcasting. Вроде так это называется...
    #33685954
Landanan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
К вопросу о том, зачем так делать.
Задание такое в универе: написать один базовый класс. Потом создать 3 наследственных класса.

в главной проге должно быть что-то в этом роде:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
int main()
{
   int numOfEntries;
   cin >> numOfEntries;

   Base **list=new Base *[numOfEntries];

   char id;
   for (int i= 0 ; i<numOfEntries; i++)
   {
      cin >> id;
      if (id=='A') list[i] = new DerivedOne;
      else if (id=='B') list[i] = new DerivedTwo;
      else if (id=='C') list[i] = new DerivedThree;
      else cout << "Identifier not recognized." << endl;
   }

   list[ 0 ]->setDerivedOneMember( 10 );
   list[ 1 ]->setDerivedTwoMember( 12 , 3 );
   list[ 2 ]->setDerivedThreeMember('A');
   return  0 ;
}

И всё в этом роде...Учитывая, что вся эта инфа будет считываться либо из файла, либо с клавы, по желанию юзера.

Сами классы уже готовы и работают нормально.
Однако данная система не работает, т.к. пойнтер list имеет тип Base и само-собой показывает только ту часть, которая принадлежит этому классу => я не имею доступа к членам наследственных классов через пойнтер на родительский класс...
...
Рейтинг: 0 / 0
Downcasting. Вроде так это называется...
    #33685975
Фотография Cerebrum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
как насчет DYNAMIC_DOWNCAST или STATIC_DOWNCAST
...
Рейтинг: 0 / 0
Downcasting. Вроде так это называется...
    #33686114
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cerebrumкак насчет DYNAMIC_DOWNCAST или STATIC_DOWNCAST

Таких операций нет в C++.

А что на счет "опсной" программы с dynamic_cast<>,
так там просто программа неправильная , с ошибкой.

Должно быть :
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
Base* pb = new(Base);
    pb->f();
    Deriv* pD = dynamic_cast<Deriv*>(pb)
    if(pD) 
       pD->n_member =  1 ;
    cout << "test 2 ok\n";


Ну так чтобы очень это было опасно, я бы не сказал. Вопрос идеологии. Посмотрите например на любую COM-программу, там получение интерфейсов из какого-то IUnknown - обычное дело. Это - то же самое. Только писать надо всегда правильно. Тут дело в другом, что надо про всех наследников знать,
что это знание вкодировано в программу, что новых быть не может и т.п.
...
Рейтинг: 0 / 0
Downcasting. Вроде так это называется...
    #33686156
Фотография Cerebrum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вот выдержка из afx.h
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
#define STATIC_DOWNCAST(class_name, object) \
	(static_cast<class_name*>(AfxStaticDownCast(RUNTIME_CLASS(class_name), object)))
#define STATIC_DOWNCAST_T(class_name, T1, object) \
	(static_cast<class_name<T1>*>(AfxStaticDownCast(RUNTIME_CLASS_T(class_name, T1), object)))
#define STATIC_DOWNCAST_T2(class_name, T1, T2, object) \
	(static_cast<class_name<T1, T2>*>(AfxStaticDownCast(RUNTIME_CLASS_T2(class_name, T1, T2), object)))
#else
#define STATIC_DOWNCAST(class_name, object) (static_cast<class_name*>(object))
#define STATIC_DOWNCAST_T(class_name, T1, object) (static_cast<class_name<T1>*>(object))
#define STATIC_DOWNCAST_T2(class_name, T1, T2, object) (static_cast<class_name<T1, T2>*>(object))
#endif

и

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
// RTTI helper macros/functions
const CObject* AFX_CDECL AfxDynamicDownCast(CRuntimeClass* pClass, const CObject* pObject);
CObject* AFX_CDECL AfxDynamicDownCast(CRuntimeClass* pClass, CObject* pObject);
#define DYNAMIC_DOWNCAST(class_name, object) \
	(class_name*)AfxDynamicDownCast(RUNTIME_CLASS(class_name), object)

#ifdef _DEBUG
const CObject* AFX_CDECL AfxStaticDownCast(CRuntimeClass* pClass, const CObject* pObject);
CObject* AFX_CDECL AfxStaticDownCast(CRuntimeClass* pClass, CObject* pObject);
#define STATIC_DOWNCAST(class_name, object) \
	(static_cast<class_name*>(AfxStaticDownCast(RUNTIME_CLASS(class_name), object)))
#define STATIC_DOWNCAST_T(class_name, T1, object) \
	(static_cast<class_name<T1>*>(AfxStaticDownCast(RUNTIME_CLASS_T(class_name, T1), object)))
#define STATIC_DOWNCAST_T2(class_name, T1, T2, object) \
	(static_cast<class_name<T1, T2>*>(AfxStaticDownCast(RUNTIME_CLASS_T2(class_name, T1, T2), object)))
#else
#define STATIC_DOWNCAST(class_name, object) (static_cast<class_name*>(object))
#define STATIC_DOWNCAST_T(class_name, T1, object) (static_cast<class_name<T1>*>(object))
#define STATIC_DOWNCAST_T2(class_name, T1, T2, object) (static_cast<class_name<T1, T2>*>(object))
#endif
...
Рейтинг: 0 / 0
Downcasting. Вроде так это называется...
    #33686450
Landanan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Метод (Derived*)(list[0]) помог, спасибо!

А можно ли конвертировать из Base в Derived навсегда?

Чтобы потом, например, мог отобразить весь лист одним циклом:

Код: plaintext
1.
for (int i= 0 ; i<numOfEntries; i++)
   cout << *list << endl;

?
В данном листе находятся пойнтеры на 3 разных класса, и я не знаю какой тип где. Вот можно как-то сделать, чтобы при назначении пойнтера (list [i]=new Something;), менялся его тип?
...
Рейтинг: 0 / 0
Downcasting. Вроде так это называется...
    #33687996
Alex_VC
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
[quot MasterZivПосмотрите например на любую COM-программу, там получение интерфейсов из какого-то IUnknown - обычное дело. Это - то же самое. Только писать надо всегда правильно. Тут дело в другом, что надо про всех наследников знать,
что это знание вкодировано в программу, что новых быть не может и т.п.[/quot]
Если мне не изменяет память, то там используется reinterpret_cast...
...
Рейтинг: 0 / 0
Downcasting. Вроде так это называется...
    #33690085
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если мне не изменяет память, то там используется reinterpret_cast...

Да там все что хочешь может использоваться. Хоть C-style cast. Дело не в этом, а в том, что когда получаешь указатель на новый интерфейс, прежде чем с ним работать, надо его проверить, есть ли он вообще. Так и здесь, полная аналогия.
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / Downcasting. Вроде так это называется...
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]