LINUX.ORG.RU

QMPlay2 приведение кода к стандарту c++17

 , ,


0

1

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

может кто то сталкивался с такими трабблами при наследовании от QThread?


Ты точно не перепутал ссылку на строчку кода? Потому что я не вижу ничего криминального. playC.vThr имеет тип class VideoThr final : public AVThread, т.е. наследник AVThread. Приведение к родителю обычное дело. Правда это нужно делать через static_cast, а не сишными скобочками. А то можно огрести проблем.

создать родительский класс

Здесь нет создания. Это приведение типа одного указателя к другому.

ox55ff ★★★ ()
Ответ на: комментарий от ox55ff

понятно чо тут нет создания наследника напрямую в коде, но однако я считаю чо именно енто хотел сделать разраб...

попробуй сфоркай код и создай полиморфный родительский тип в ентой строке — у меня не удалось...
делал так:

std::unique_ptr<AVThread> aThr = std::make_unique<AudioThr>(playC.aThr), vThr = std::make_unique<VideoThr>(playC.vThr);

но увы — грит чо нету конструктора... — а его и правда нету

конструкторы копирования и перемещения удалены тут

а так же нельзя скастить не interpret_cast'ом енти типы между собой в такой взаимосвязи, как в коде...

safocl ()
Последнее исправление: safocl (всего исправлений: 2)
Ответ на: комментарий от ox55ff

на счет отсутствия криминального — ты точно понимаеш чо там тварится? (ну или я просто думаю не верно)

потому, что если взять дочерний класс с доп функционалом и скастить его к родительскому то получится кастрированный дочерний класс до родительского... Полиморфизма не будет. Вопрос — зачем тогда вообще использовать дочерний класс?

safocl ()
Ответ на: комментарий от safocl

тут появляется ошибка:

DemuxerThr.cpp:143:35: error: no viable conversion from 'unique_ptr<AudioThr>' to 'unique_ptr<AVThread>'
unique_ptr.h:242:12: note: candidate constructor template not viable: no known conversion from 'typename _MakeUniq<AudioThr>::__single_object' (aka 'unique_ptr<AudioThr>') to 'std::nullptr_t' (aka 'nullptr_t') for 1st argument
unique_ptr.h:249:7: note: candidate constructor not viable: no known conversion from 'typename _MakeUniq<AudioThr>::__single_object' (aka 'unique_ptr<AudioThr>') to 'std::unique_ptr<AVThread, std::default_delete<AVThread> > &&' for 1st argument
unique_ptr.h:406:7: note: candidate constructor not viable: no known conversion from 'typename _MakeUniq<AudioThr>::__single_object' (aka 'unique_ptr<AudioThr>') to 'const std::unique_ptr<AVThread, std::default_delete<AVThread> > &' for 1st argument
unique_ptr.h:263:2: note: candidate template ignored: requirement '__and_<std::__and_<std::is_convertible<AudioThr *, AVThread *>, std::__not_<std::is_array<AudioThr> > >, std::is_convertible<std::default_delete<AudioThr>, std::default_delete<AVThread> > >::value' was not satisfied [with _Up = AudioThr, _Ep = std::default_delete<AudioThr>]
unique_ptr.h:273:2: note: candidate template ignored: could not match 'auto_ptr' against 'unique_ptr'

safocl ()
Ответ на: комментарий от safocl

std::unique_ptr<AVThread> aThr = std::make_unique<AudioThr>(playC.aThr)

чё это за дичь? Там по коду aThr это не владеющий указатель, там нигде нет освобождения aThr, зачем ему быть unique_ptr, если он не владеет объектом?

Почитай вообще про указатели и С++17. Привести к С++17, это не просто заменить все указатели на unique_ptr/shared_ptr...

fsb4000 ★★ ()
Ответ на: комментарий от safocl

Это вообще очень распространённая практика.

то получится кастрированный дочерний класс

Нет, с классом ничего не произойдёт. Просто ты теперь не сможешь обратиться к методам, которые есть в дочернем классе, но нет в родительском.

зачем тогда вообще использовать дочерний класс?

Если ты читал про полиморфизм, то там были примеры. Например с геометрическими фигурами и методом draw.

ox55ff ★★★ ()
Ответ на: комментарий от safocl
std::unique_ptr<AVThread> aThr = std::make_unique<AudioThr>(playC.aThr)

Что ты хочешь здесь сделать? Если обернуть сырой указатель playC.aThr, то это делается через std::unique_ptr, а не std::make_unique. Но здесь даже так нельзя сделать, т.к. будет двойное освобождение памяти.

ox55ff ★★★ ()
Ответ на: комментарий от safocl

Нет, ты делаешь неправильно. В лучшем случае ты создашь копию объекта и плеер будет работать неправильно. Если хочешь умные указатели, то нужно везде по коду обернуть aThr в std::shared_ptr, причём создавать его только в одном месте. В остальных только копирование. Тебе выше fsb4000 всё верно сказал.

ox55ff ★★★ ()
Последнее исправление: ox55ff (всего исправлений: 1)
Ответ на: комментарий от ox55ff

Приведение к родителю обычное дело. Правда это нужно делать через static_cast

Код не смотрел, но в общем случае к родителю, как и к наследнику, стоит приводить через dynamic_cast, а не static_cast

XMs ★★★★★ ()
Ответ на: комментарий от XMs

К родителю то зачем дайнемиком? На этапе компиляции точно известен граф наследования. И от static_cast будет ошибка, если каст неправильный. С dynamic_cast нужно в RTTI лезть и с nullptr сравнивать результат. В общем много мороки и оверхеда.

ox55ff ★★★ ()
Ответ на: комментарий от safocl

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

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

safocl ()
Ответ на: комментарий от safocl

так же будет делаться если просто делать обычный указатель

нет. Так только в языках со сборкой мусора. C++ к ним не относится. Пока не сделаешь delete ptr; объект будет жить.

ox55ff ★★★ ()
Ответ на: комментарий от ox55ff

ну енто понятно, но мы же создаем новый объект make_unique'м, мы не копим указатель из playC, а разыменовываем его.

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

да и вообще я убрал создание родительского класса, т.к. нету смысла как я вижу код — по коду используется только сравнивание такого указателя на nullptr и вызов метода lock() из родительского класса, т.к. ентот метод не виртуальный.

safocl ()
Последнее исправление: safocl (всего исправлений: 1)
Ответ на: комментарий от safocl

Судя по коду тебе не нужен новый объект. Тебе нужен доступ к старому. Зачем ты хочешь создать новый объект? Этим просто поломаешь логику программы.

Впрочем, если так хочется, то я не могу тебе запретить.

ox55ff ★★★ ()
Ответ на: комментарий от ox55ff

Приведение к родителю обычное дело. Правда это нужно делать через static_cast, а не сишными скобочками

Коллега, преобразовывать объект производного класса к типу родительского класса не нужно в принципе через специальные операции приведения. Это осуществляется простым присваиванием, если не нарушены некоторые условия. Специальные операции приведения как раз нужны для преобразования от родительского к производному.

rumgot ★★★★★ ()
Последнее исправление: rumgot (всего исправлений: 4)
Ответ на: комментарий от safocl

может не понятно что я имею ввиду — класс QWindow енто наследник класса QObject, и тут родитель кастится в наследника...

статиком скастилось вроде норм, но не понятно — для чего такой прием, нормальный ли он или его необходимо править?

safocl ()
Ответ на: комментарий от safocl

в основном не понятно как компилятор выделяет память под новые поля наследника, если рядом нет достаточной свободной памяти для такого выделения?

вроде када читал стандарт 17 года не видил ничего подобного... может плоха читал канечн.

safocl ()
Ответ на: комментарий от EXL

ну в общем я сделал статик каст и ошибок нет, однако на сколько такое поведение нормально?
в вопросе приведения из указателя на объект наследника в указатель на объект родителя все понятно — там просто не используются новый функционал наследника...
но када наоборот — то получается, куда расширяет компилятор меньший класс в больший? если места рядом нет свободного, все плотно укомплектовани? реаллокация памяти для класса родителя делается или как?

просто впервые вижу такой прием, и не понимаю на сколько он архитектурно верен даже если енто норм поведение?
и чо будет если его сделать еще вдобавок многими другими классами наследниками?

допустим:
базовый класс А;
от него наследуются классы B, C, D, E и т.д. ...
а ведь в qt енто как раз так все и есть...
что получится если создаем указатель на класс родителя.
A * a = new a();
потом создаем из него указатель на наследника B
B * b = static_cast<B *>(a);

а после создаем таким же методом другие объекты класса наследников
C * c = static_cast<C *>(a);
D * d = static_cast<D *>(a);
E * e = static_cast<E *>(a);

и в каждом из них будет какой то новый доп функционал....
получится чо аллокация для объекта класса родителя разрастется?
и чо будет если в классах наследников определены одноименные поля?

safocl ()
Последнее исправление: safocl (всего исправлений: 2)
Ответ на: комментарий от safocl

Там фильтр через условие isWindowType(). Проверка на то, что объект переданный по указателю QObject * является экземпляром класса QWindow. То есть там преобразований про которые ты говоришь.

И ниже в фильтре через switch используется точно такой же пример со static_cast, который ты видимо не заметил.

EXL ★★★★★ ()
Ответ на: комментарий от EXL

но ведь ты не будешь отрицать чо указатель QWindow *win создан из указателя QObject *watched???
получается чо создается указатель win который использует уже созданный в памяти блок объекта QObject *watched... а дополнительные для функционирования класса QWindow поля где создались?

я проверял на тестовом примере — область начала памяти таких объектов одна и таже, т.е. адрес указателей один... но размер разный, соответственно у наследника больше на количество доп полей... однако не понятно, где енти поля находятся в памяти, вроде же стандарт гарантирует чо поля класса находятся подобно массивам — вплотную, — из-за чего появляются и предупреждения о дополнительном выравнивании...
или компилятор резервирует место при таком коде для всех полей классов наследников созданных таким способом из родителя на этапе компиляции?

или ты имееш ввиду что туда в функцию передается именно наследник класса QObject — класс QWindow ? и только в ентом случае будет все остальное? Для реализации полиморфизма...

однако даже енто не отменяет моего тестового опыта, где такого не происходит...

safocl ()
Последнее исправление: safocl (всего исправлений: 2)
Ответ на: комментарий от safocl

Тебе нужно почитать какую-нибудь книгу по основам C++. Потому что у тебя сейчас каша в голове. В C++ приведение из указателя на объект родительского класса в указатель на объект производного класса нужно использовать ТОЛЬКО ТОГДА, КОГДА В ПАМЯТИ ПО ЭТОМУ УКАЗАТЕЛЮ НАХОДИТСЯ ОБЪЕКТ ЭТОГО ПРОИЗВОДНОГО КЛАССА ЛИБО ЕГО ПОТОМКА! ИНАЧЕ (если по этому указателю в памяти расположен объект родительского класса или объект вообще не из данной иерархии наследования (если используется reinterpret_cast)) ЭТО НЕОПРЕДЕЛЕННОЕ ПОВЕДЕНИЕ И ТАК ДЕЛАТЬ НЕЛЬЗЯ (и кстати dynamic_cast при этом вернет nullptr в случае указателя и сгенерирует исключение в случае ссылки).

rumgot ★★★★★ ()
Последнее исправление: rumgot (всего исправлений: 2)
Ответ на: комментарий от safocl

создаем указатель на класс родителя

Нет. Никакой указатель ты не создаёшь, ты создаёшь объект и присваиваешь его адрес переменной. Ещё раз. У тебя два действия: 1. создать объект в памяти

new A();
2. присвоить адрес этого объекта в памяти в переменную типа указатель
A *a = адрес только что созданного объекта

fluorite ★★★★★ ()
Ответ на: комментарий от fluorite

ты помоему чото сказал масло масленное... тафтологиш...
как ты не упирайся но A *a енто указатель... — т.е. создаеш указатель на память в которой хранится объект, точнее на ее начало, а уж компилятор знает размер.

safocl ()
Ответ на: комментарий от rumgot

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

safocl ()
Ответ на: комментарий от safocl

Да, я об этом. Понимаешь ли. Если у тебя в памяти лежит объект родительского класса, ты преобразовал указатель в указатель на объект производного класса. То может программа и не упадет, и может поля производного даже чем-то и заполнятся, и может даже как-то работать все будет. Но в этом и суть undefined behavior: как оно будет никто не знает и ничего не гарантирует. Еще раз повторяю: в данном случае операции преобразования для того чтобы преобразовывать тип указателя/ссылки, при том, что тип объекта в памяти остается постоянным. К тому же dynamic_cast ясно дает понять, что данное преобразование не корректно.

rumgot ★★★★★ ()
Ответ на: комментарий от fluorite

Я полагаю что он имеет ввиду, что конструкция:

A *a = new A;

Кроме создания объекта класса A,также создает переменную-указатель на объект класса A.

rumgot ★★★★★ ()
Последнее исправление: rumgot (всего исправлений: 4)

народ кто может подсказать, как быть тут?
определение:

Q_REQUIRED_RESULT static QByteArray fromRawData(const char *, int size);


необходимо конст чар сделать первый арг, а он unsigned char из самого qt доставляется из функции const uchar *constBits() const; класса QImage

придется довериться логике проги и вдуть реинтерпреткаст?

safocl ()
Последнее исправление: safocl (всего исправлений: 1)
Ответ на: комментарий от safocl
((char* )&bs2bdp->lfs)[--loopv]

Осуществляется доступ к члену lfs структуры через указатель, затем берется адрес этого члена, приводится к указателю на char и далее осуществляется доступ по индексу(типа как к массиву). Причем переменная loopv сначала уменьшается на 1, потом используется в качестве индекса.

rumgot ★★★★★ ()
Ответ на: комментарий от safocl

Нормально или нет - это ты уже у автора кода спрашивай. Я лично в своем коде подобных низкоуровннвых конструкций стараюсь избегать. Но это не значит, что такой код плохой или ошибочный, просто мне субъективно не нравится такой стиль.

rumgot ★★★★★ ()
Последнее исправление: rumgot (всего исправлений: 2)
Ответ на: комментарий от safocl

а енто нормально, что мне выдет такую ошибку при сборке:

/usr/include/qt/QtCore/qmetatype.h:1416:41: error: cannot cast 'Module' to its protected base class 'QObject'
        enum { Value = sizeof(checkType(static_cast<T*>(nullptr))) == sizeof(yes_type) };


т.е. qt не собирается с std=c++17?

safocl ()
Последнее исправление: safocl (всего исправлений: 1)