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

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

03.01.2020, 22:54. Показов 6939. Ответов 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
Ответ Создать тему
Новые блоги и статьи
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её. Последовательность действий:. . .
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru