Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.57/30: Рейтинг темы: голосов - 30, средняя оценка - 4.57
0 / 0 / 0
Регистрация: 18.09.2018
Сообщений: 4

Восходящее преобразование массива производного класса к родительскому?

03.01.2020, 22:54. Показов 6991. Ответов 114

Студворк — интернет-сервис помощи студентам
Есть два класса base_Class(родитель) и derived_Class(потомок)
Есть некая виртуальная функция в base_Class которая принимает в качестве параметра массив объектов класса f(base_Class **mass)
Чтобы воспользоваться данной функцией для производного класса, необходимо привести массив производного класса к массиву родительского
Массивы: base_Class *baseMass[100], derived_Class *derivedMass[100]
Как произвести такое приведение типов?
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
03.01.2020, 22:54
Ответы с готовыми решениями:

Определить обработчик исключений на преобразование указателя базового класса на указатель производного класса
Класс В является производным от класса А. Определить обработчик исключительной ситуации на преобразование указателя базового класса А на...

Восходящее преобразование
помогите пожайлуста разобраться, почему выдаёт ошибку... public class A{ public int f1(){return 1;}; public int...

Восходящее преобразование, объяснить код
Всем привет! Мне не понятен один момент в восходящем преобразовании. Есть два класса: один базовый, другой производный от базового. В...

114
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
06.01.2020, 04:03
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от IGPIGP Посмотреть сообщение
В частности в данном случае сказано о том что типы "подобны/similar" если совпадают cv сигнатуры
???
В определении similar types не сказано, что cv-сигнатуры должны совпадать.
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
06.01.2020, 12:05
Цитата Сообщение от rat0r Посмотреть сообщение
В определении similar types не сказано, что cv-сигнатуры должны совпадать.
может я и не верно говорю. Вот фрагмент который я понял как идентичность по cv сигнатуре и U
Two types T1 and T2 are similar if they have cv-decompositions with the same n such that corresponding Pi components are the same and the types denoted by U are the same.
Я это понял, как требование идентичности, так как пошаговая идентичная декомпозиция даёт идентичность cv-сигнатур, а идентичность U это идентичность того что в остатке.

Добавлено через 8 минут
Но если исходить из
Цитата Сообщение от IGPIGP Посмотреть сообщение
данное условие - тавтология. И может быть принято как достаточное условие в качестве отправной точки (неуклюжий вариант). А далее можно формулировать случаи когда возможны отличия
то вот это разъяснение возможного отличия от отправной точки
A prvalue expression of type T1 can be converted to type T2 if the following conditions are satisfied, where cvji denotes the cv-qualifiers in the cv-qualification signature of Tj:60
(3.1)
T1 and T2 are similar.
Можно трактовать как добро на случай если T1=Base* , a T2=Derived* (наш случай).
Там далее указаны требуемые условия по cv когда они допускают отличия но важно же не это. Важно что мы знаем что преобразование
Derived* в Base* допускается языком. А тот факт что, скажем, возможно Derived* в const Base* не имеет к нашему случаю отношения.
0
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
06.01.2020, 13:25
Цитата Сообщение от IGPIGP Посмотреть сообщение
так как пошаговая идентичная декомпозиция даёт идентичность cv-сигнатур
Лично я ничего такого не вижу. Где сказано, что она что-то "даёт"?
C++
1
2
3
4
int main() {
  char* pc;
  char* const* pcc = &pc;
}
Код выше валидный? Почему?

Добавлено через 1 минуту
Цитата Сообщение от IGPIGP Посмотреть сообщение
а идентичность U это идентичность того что в остатке
Идентичность U это идентичность полученных типов после разименования указателя.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
06.01.2020, 13:54
Цитата Сообщение от Azazel-San Посмотреть сообщение
Код выше валидный? Почему?
Сигнатуры в вашем коде не идентичны.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
06.01.2020, 14:19
Цитата Сообщение от rat0r Посмотреть сообщение
читать значение из объекта типа der* через glvalue с типом base* это банально нарушение т.н. strict aliasing rules.
пруф?
0
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
06.01.2020, 16:22
Цитата Сообщение от IGPIGP Посмотреть сообщение
Сигнатуры в вашем коде не идентичны.
Ну, да.
Вы достаточно наблюдательны.
Цитата Сообщение от IGPIGP Посмотреть сообщение
Можно трактовать как добро на случай если T1=Base* , a T2=Derived* (наш случай).
Там далее указаны требуемые условия по cv когда они допускают отличия но важно же не это. Важно что мы знаем что преобразование
Derived* в Base* допускается языком. А тот факт что, скажем, возможно Derived* в const Base* не имеет к нашему случаю отношения.
Соглашусь, derived* в base* вполне валидное преобразование, но derived** в base** - уже не уверен.
Правда я так и не понял к чему здесь
Цитата Сообщение от https://timsong-cpp.github.io/cppwp/n4659/expr.add#6
if the expressions P or Q have type “pointer to cv T”, where T and the array element type are not similar
Там же нету cv T.

Добавлено через 49 минут
И, по-моему, у hoggy как раз все ок, ведь у него массив указателей, а не массив объектов:
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
struct base {    
    virtual ~base() {}
    virtual void print() = 0;
};
 
struct derived final : base {
    int j;
    
    void print() override { std::cout << "[derived::print] j = " << j << "\n"; }
};
 
int main() {    
/*
    derived darr[2]; // an array of objects
    darr[0].j = 1;
    darr[1].j = 2;
    
    base* bp = darr;
    bp[1].print(); // ub, throws SIGSEGV
*/
    derived* dparr[2]{new derived(), new derived()}; // an array of pointers
    dparr[0]->j = 1;
    dparr[1]->j = 2;
    
    base** bpp = (base**)dparr; // same as reinterpret_cast<base**>(dparr)
    bpp[1]->print(); // valid
}
И это вполне логично, т.к. арифметика указателей не учитывает размеры полиморфных объектов.
1
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
06.01.2020, 16:45
Цитата Сообщение от Azazel-San Посмотреть сообщение
Правда я так и не понял к чему здесь
Сообщение от https://timsong-cpp.github.io/... expr.add#6
if the expressions P or Q have type “pointer to cv T”, where T and the array element type are not similar
Там же нету cv T.
In this International Standard, the notation cv (or cv1, cv2, etc.), used in the description of types, represents an arbitrary set of cv-qualifiers, i.e., one of {const}, {volatile}, {const, volatile}, or the empty set.
https://timsong-cpp.github.io/... ualifier#5
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
06.01.2020, 17:08
Цитата Сообщение от Azazel-San Посмотреть сообщение
но derived** в base** - уже не уверен.
в общем случае каст провоцирует UB.

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

Цитата Сообщение от Azazel-San Посмотреть сообщение
И, по-моему, у hoggy как раз все ок, ведь у него массив указателей
и одиночное наследование.
1
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
06.01.2020, 17:18
Цитата Сообщение от Azazel-San Посмотреть сообщение
по-моему, у hoggy как раз все ок
Хотя мы все еще можем выстрелить себе в ногу.
Как уже говорилось преобразование derived* в base* вполне валидное и не требует никаких танцев с бубнами, но вот уже derived** в base** можно преобразовать только через reinterpret. Это из-за того, что после разыменования base** мы можем получить base*, который указывает уже не на derived, а на некого другого наследника, что не очень круто.

Добавлено через 1 минуту
Цитата Сообщение от hoggy Посмотреть сообщение
и одиночное наследование.
Да.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
06.01.2020, 17:20
Цитата Сообщение от Azazel-San Посмотреть сообщение
Это из-за того, что после разыменования base** мы можем получить base*, который указывает уже не на derived, а на некого другого наследника
в варианте hoggy - не можешь.
0
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
06.01.2020, 17:24
Цитата Сообщение от hoggy Посмотреть сообщение
в общем случае каст провоцирует UB.
Еще примерчик, в дополнение к твоему.
Кликните здесь для просмотра всего текста
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
struct base {    
    virtual ~base() {}
    virtual void print() = 0;
};
 
struct derived : base {
    int i;
    
    void print() override { std::cout << "[derived::print] j = " << i << '\n'; }
    virtual void do_nothing() { std::cout << "derived::do_nothing\n"; }
};
 
struct bad_guy : base {    
    void print() override { }
    virtual void hack() { std::cout << "bad_guy::hack\n"; }
};
 
int main() {
 
    derived* dparr[2]{new derived(), new derived()}; // an array of pointers
    
    dparr[1]->do_nothing(); // calls derived::do_nothing
    
    base** bpp = (base**)dparr; // same as reinterpret_cast<base**>(dparr)
    bad_guy really_bad_one;
    bpp[1] = &really_bad_one;
    
    dparr[1]->do_nothing(); // calls bad_guy::hack
 
}

Так же, наверное, важно упомянуть наличие виртуальных таблиц у наследников, благодаря чему это работает.
1
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
06.01.2020, 17:25
Цитата Сообщение от Azazel-San Посмотреть сообщение
Это из-за того, что после разыменования base** мы можем получить base*, который указывает уже не на derived, а на некого другого наследника, что не очень круто.
вроде нет, указывать он будет туда же, а вот то что (base**)ptr+1 и (der**)ptr+1 будут указывать в одно место, стандарт уже не гарантирует (хотя мне трудно представить, зачем может понадобится такая реализация)
1
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
06.01.2020, 17:30
Цитата Сообщение от hoggy Посмотреть сообщение
в варианте hoggy - не можешь.
Ну, я это написал к тому, что вообще такое может случится и это стоит учитывать, у тебя так не получится сделать, да.
И мой пример выше, просто пример, что так тоже может быть.

Добавлено через 2 минуты
Цитата Сообщение от zayats80888 Посмотреть сообщение
указывать он будет туда же
Это если кто-то не скажет ему указывать не туда же )
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
06.01.2020, 17:35
Цитата Сообщение от Azazel-San Посмотреть сообщение
И мой пример выше, просто пример, что так тоже может быть.
кстати поэтому я писал, что "лучше" кастить к base*const*
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
06.01.2020, 17:40
Цитата Сообщение от Azazel-San Посмотреть сообщение
Еще примерчик, в дополнение к твоему.
важно понимать,
что косяк здесь не в двойном касте.
а в некорректной ре-интерпритации типов.

твой пример можно подсократить вообще без каста двойного указателя,
но суть не изменится:

C++
1
2
3
4
5
6
7
8
int main() 
{
    derived* dparr[2]{new derived(), new derived()};
    
    bad_guy really_bad_one;
    dparr[1] = reinterpret_cast<derived*>(&really_bad_one); 
    dparr[1]->do_nothing();
}
1
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
06.01.2020, 17:50
Цитата Сообщение от zayats80888 Посмотреть сообщение
кстати поэтому я писал, что "лучше" кастить к base*const*
Ну, раз пошла такая пьянка, то я бы сказал, что лучше вообще так не делать, если есть возможность

Добавлено через 10 минут
Цитата Сообщение от hoggy Посмотреть сообщение
важно понимать,
что косяк здесь не в двойном касте.
а в некорректной ре-интерпритации типов.
твой пример можно подсократить вообще без каста двойного указателя,
но суть не изменится:
Но мне кажется, в том числе и из-за этой ре-интерпритации типов и запрещен неявный каст derived** в base**, и надо явно кастить?
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
06.01.2020, 18:08
Цитата Сообщение от Azazel-San Посмотреть сообщение
Но мне кажется, в том числе и из-за этой ре-интерпритации типов и запрещен неявный каст derived** в base**, и надо явно кастить?
конечно.
все неявные касты обязаны быть безопасными.
хочешь сделать что-то потенциально опасное - делай явно.

derived** в base** не просто опасен,
он классифицируется как UB,
потому что в общем случае корректность результата не может быть гарантирована
и по этой причине, лучше вообще так не кастить.

конечно, если у тебя дилема:
делать медленную копию массива из 10'000'000 элементов,
или кастануть за мгновение, тогда есть резон.

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

и если, допустим, это - одноразовая акция, тогда может фиг бы с ним,
сделаем честную копию массива?
пускай медленно. зато безопасно, да и делаем только один раз.
2
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
06.01.2020, 19:11
Цитата Сообщение от hoggy Посмотреть сообщение
читать значение из объекта типа der* через glvalue с типом base* это банально нарушение т.н. strict aliasing rules.
пруф?
http://eel.is/c++draft/basic.lval#11
Цитата Сообщение от hoggy Посмотреть сообщение
derived** в base** не просто опасен,
он классифицируется как UB
Хочешь сказать, у кода derived d; derived* dptr = &d; reinterpret_cast<base**>(&dptr); неопределённое поведение?

Добавлено через 8 минут
Цитата Сообщение от IGPIGP Посмотреть сообщение
может я и не верно говорю. Вот фрагмент который я понял как идентичность по cv сигнатуре и U
Что такое "cv сигнатура"?
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
06.01.2020, 19:46
Цитата Сообщение от rat0r Посмотреть сообщение
http://eel.is/c++draft/basic.lval#11
ты ничего не путаешь?
какое отношение твоя ссылка имеет к твоему утверждению?

Цитата Сообщение от rat0r Посмотреть сообщение
читать значение из объекта типа der* через glvalue с типом base* это банально нарушение т.н. strict aliasing rules.
какое вообще отношение твоя ссылка имеет к strict aliasing rules?

Цитата Сообщение от rat0r Посмотреть сообщение
Хочешь сказать, у кода derived d; derived* dptr = &d; reinterpret_cast<base**>(&dptr); неопределённое поведение?
хочу сказать, что неопределенное поведение программы - это следствие
работы с некорректными данными.

поведение представленного тобою фрагмента кода вполне себе определенно.
а вот что будет дальше,
когда ты попробуешь использовать результат reinterpret_cast<base**>(&dptr) - это вопрос.
0
06.01.2020, 19:46

Не по теме:

Цитата Сообщение от rat0r Посмотреть сообщение
Хочешь сказать, у кода derived d; derived* dptr = &d; reinterpret_cast<base**>(&dptr); неопределённое поведение?
мне кажется речь шла о *reinterpret_cast<base**>(&dptr)

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
06.01.2020, 19:46
Помогаю со студенческими работами здесь

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

Восходящее и нисходящее преобразование (Upcasting and Downcasting)
Посоветуйте литературу по данному вопросу в разрезе С++ ну или простыми словами что это, для чего нужно заранее спасибо

Неявное восходящее преобразование при защищенном/закрытом наследовании
Здравствуйте. Читаю книгу Стивена Прата по C++. Попался непонятный момент: в одной таблице (в таблице 14.1 в 6-й рус. редакции на стр....

Как сложить объект базового класса с объектом производного(наследуемого класса)
Как умножить объект базового класса с объектом производного(наследуемого класса): ozenka - объект базового класса, а ves- производного ...

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


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru