Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/4: Рейтинг темы: голосов - 4, средняя оценка - 5.00
105 / 7 / 1
Регистрация: 27.04.2015
Сообщений: 251

Ошибка преобразования собственных типов

21.10.2023, 02:16. Показов 813. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброй ночи.
Допустим есть такой код
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <QApplication>
#include "mainwindow.h"
#include "QDebug"
 
class ChadParrent
{
public:
    ChadParrent()
    {
        qDebug() << "ChadParrent";
    }
    virtual void say()
    {
        qDebug() << "ChadParrent - say";
    }
    virtual ~ChadParrent(){};
};
 
class ChadTunyChild: public ChadParrent
{
public:
    ChadTunyChild()
    {
        qDebug() << "ChadTunyChild";
    }
    void say() override
    {
        qDebug() << "ChadTunyChild - say";
    }
    ~ChadTunyChild(){}
};
 
class ChadChild: public ChadParrent
{
public:
    ChadChild()
    {
        qDebug() << "ChadChald";
    }
    void say() override
    {
        qDebug() << "ChadChald - say";
    }
    operator ChadTunyChild() const
        {
            return *new ChadTunyChild;
        }
    ~ChadChild(){}
};
 
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    std::shared_ptr<ChadParrent> c0 = std::make_shared<ChadParrent>();
    c0->say();
    std::shared_ptr<ChadChild> c1 = std::static_pointer_cast<ChadChild>(c0);
    c1->say();
    std::shared_ptr<ChadTunyChild> c2 = std::static_pointer_cast<ChadChild>(c1); //тут ошибка
    c2->say();
    MainWindow w;
    w.show();
    return a.exec();
}
Вроде я написал перегрузку для преобразования ChadChild в ChadTunyChild, но std::static_pointer_cas чего-то надо (59я строка). Может для умных указателей перегрузка преобразования пишется как-то иначе ?

Добавлено через 3 минуты
кстати сейчас попробовал
C++
1
2
    ChadParrent c0;
    ChadChild c1 = static_cast<ChadChild>(c0);
Мне выдало ошибку

Code
1
2
3
main.cpp:63:20: No matching conversion for static_cast from 'ChadParrent' to 'ChadChild'
main.cpp:34:7: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'ChadParrent' to 'const ChadChild' for 1st argument
main.cpp:37:5: candidate constructor not viable: requires 0 arguments, but 1 was provided
это вызвало у меня ступор, какой еще один аргумент в конструкторе? Я же не пишу аргументов.
1
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
21.10.2023, 02:16
Ответы с готовыми решениями:

Ошибка преобразования типов
В чем именно я ошибся,если код ошибки #include &lt;iostream&gt; #include &lt;stdlib.h&gt; #include &lt;string&gt; #include &lt;ctype.h&gt; ...

Динамический массив структур. Ошибка преобразования типов
Всем привет есть задачка на структуры. Нужно через структуру В сделать динамический массив структуры А. Написал функцию, но компилятор...

Перегрузил операцию преобразования типов данных (класс -> класс) но выскакивает ошибка компиляции
Здравствуйте, учил перегрузку операции преобразования типов данных, пробую объект SecondClass преобразовать в объект BasicClass. ...

13
Диванный эксперт
Эксперт С++
 Аватар для Max Dark
2550 / 2064 / 971
Регистрация: 09.10.2013
Сообщений: 4,793
Записей в блоге: 4
21.10.2023, 02:29
Цитата Сообщение от Anton1978 Посмотреть сообщение
std::shared_ptr<ChadTunyChild> c2 = std::static_pointer_cast<ChadChild>(c1); //тут ошибка
Все правильно.
Вы пытаетесь преобразовать два несвязанных типа к друг другу.
0
105 / 7 / 1
Регистрация: 27.04.2015
Сообщений: 251
21.10.2023, 02:50  [ТС]
До меня дошло, что если вот так преобразовывать
C++
1
2
3
4
    ChadParrent c0;
    c0.say();
    ChadChild c1 = static_cast<ChadChild>(c0);
    c1.say();
То вызывается конструктор объекта, а если так
C++
1
2
3
4
    std::shared_ptr<ChadParrent> c0 = std::make_shared<ChadParrent>();
    c0->say();
    std::shared_ptr<ChadChild> c1 = std::static_pointer_cast<ChadChild>(c0);
    c1->say();
то не вызывается конструктор объекта, а вызывается перегруженный оператор. Когда разберешься не сложно.
Хотя один момент всё-же ускользает.
если оставить такой код
C++
1
2
3
4
5
    std::shared_ptr<ChadParrent> c0 = std::make_shared<ChadParrent>();
    c0->say();
    std::shared_ptr<ChadChild> c1 = std::static_pointer_cast<ChadChild>(c0);
    qDebug() << typeid(c1).name();
    c1->say();
то я получу такой вывод
Code
1
2
3
4
ChadParrent
ChadParrent - say
St10shared_ptrI9ChadChildE
ChadParrent - say
получается что у умного указателя c1 вызывает say() класса родителя, почему не понятно.
1
Диванный эксперт
Эксперт С++
 Аватар для Max Dark
2550 / 2064 / 971
Регистрация: 09.10.2013
Сообщений: 4,793
Записей в блоге: 4
21.10.2023, 03:02
Anton1978, ИМХО, Вы наткнулись на те грабли, о которых мало кто знает.
У меня есть предположение, почему так, но вот сформулировать ответ не могу.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12919 / 6787 / 1817
Регистрация: 18.10.2014
Сообщений: 17,169
21.10.2023, 07:39
Цитата Сообщение от Anton1978 Посмотреть сообщение
Вроде я написал перегрузку для преобразования ChadChild в ChadTunyChild
И что? Какое отношение эта перегрузка может иметь к функциональности std::static_pointer_cast? Почему вы решили, что std::static_pointer_cast должен ей пользоваться?

Ваш код пытается выполнять преобразование ChadChild * в ChadTunyChild *. Никакие "перегрузки" не имеют к этому никакого отношения. Это кросс-каст указателей. Крост каст указателей умеет выполнять только dynamic_cast (std::dynamic_pointer_cast), но и то только, разумеется, если целевой объект существует. В вашем случае его не существует.

Цитата Сообщение от Anton1978 Посмотреть сообщение
а если так
C++
1
2
3
4
    std::shared_ptr<ChadParrent> c0 = std::make_shared<ChadParrent>();
    c0->say();
    std::shared_ptr<ChadChild> c1 = std::static_pointer_cast<ChadChild>(c0);
    c1->say();
то не вызывается конструктор объекта, а вызывается перегруженный оператор. Когда разберешься не сложно.
??? Какой еще "перегруженный оператор"? Покажите мен пальцем этот "перегруженный оператор" у вас в коде.

Никакого "перегруженного оператора" тут не вызывается. Тут внутренне выполняется static_cast<ChadChild *>(c0.get()), то есть преобразование применено к указателю, который не указывает фактически на ChadChild. Поведение не определено, код неработоспособен.

Дальше можно не читать.

P.S. Тема строго С++-ная. За что ее перенесли в Qt - не ясно.
1
105 / 7 / 1
Регистрация: 27.04.2015
Сообщений: 251
21.10.2023, 11:39  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Ваш код пытается выполнять преобразование ChadChild * в ChadTunyChild *. Никакие "перегрузки" не имеют к этому никакого отношения. Это кросс-каст указателей. Крост каст указателей умеет выполнять только dynamic_cast (std::dynamic_pointer_cast), но и то только, разумеется, если целевой объект существует. В вашем случае его не существует.
Это я уже понял пока экспериментировал, но вообще я опирался на вот эту статью https://www.learncpp.com/cpp-t... typecasts/ и тут таких тонкостей не было, так что весьма признателен за разъяснения.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
??? Какой еще "перегруженный оператор"? Покажите мен пальцем этот "перегруженный оператор" у вас в коде.
Это я так странно назвал вот это
C++
1
2
3
4
operator ChadTunyChild() const
        {
            return *new ChadTunyChild;
        }
Но опытным путем уже установил, что моя теория не совсем верна

Добавлено через 27 минут
Эксперименты показывают, что вот такое компилируется и без перезагрузок конструктора и реализации operator ChadParrent()
C++
1
2
std::shared_ptr<ChadParrent> c0 = std::make_shared<ChadParrent>();
std::shared_ptr<ChadChild> c3 = std::static_pointer_cast<ChadChild>(c0);
а тут
C++
1
2
std::shared_ptr<ChadChild> c2 = std::make_shared<ChadChild>();
std::shared_ptr<ChadTunyChild> c4 = std::static_pointer_cast<ChadTunyChild>(c2);
что static_pointer_cast приводит к невозможности компиляции, а std::dynamic_pointer_cast вызывает крах программы (видимо привидение типов не сработало), но как тогда правильно привести один умный указатель одного типа к другому ?
Ведь зачем то существуют и static_pointer_cast и dynamic_pointer_cast ?
0
фрилансер
 Аватар для Алексей1153
6441 / 5635 / 1127
Регистрация: 11.10.2019
Сообщений: 14,981
21.10.2023, 11:49
Anton1978, ChadTunyChild и ChadChild - это два разных класса, их невозможно "привести" друг к другу. Зато можно их указатель привести к указателю на родителя

C++
1
2
3
4
    auto c1 = std::make_shared<ChadChild>();
    auto c2 = std::make_shared<ChadTunyChild>();
    std::shared_ptr<ChadParrent> p1=c1;
    std::shared_ptr<ChadParrent> p2=c2;
0
105 / 7 / 1
Регистрация: 27.04.2015
Сообщений: 251
21.10.2023, 11:55  [ТС]
Я тоже так думал, но вот целая статья о том как это делать https://www.learncpp.com/cpp-t... typecasts/
И вот такой код у меня работает
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
class ChadChild: public ChadParrent
{
public:
    ChadChild():ChadParrent()
    {
        qDebug() << "ChadChald";
    }
    void say() override
    {
        qDebug() << "ChadChald - say";
    }
    operator int()
    {
        return 25;
    }
    operator ChadTunyChild()
    {
        return ChadTunyChild();
    }
    ~ChadChild(){}
};
 
затем
 
    ChadTunyChild a1;
    ChadChild a2;
    int aa = static_cast<int>(a2);
    ChadTunyChild aaa = static_cast<ChadTunyChild>(a2);
Т.е. приведение разных типов друг к другу возможно, проблема в том как приводить друг к другу умные указатели разных типов. Уверен и это возможно.
0
фрилансер
 Аватар для Алексей1153
6441 / 5635 / 1127
Регистрация: 11.10.2019
Сообщений: 14,981
21.10.2023, 12:09
Anton1978, это не приведение друг к другу, а вызов оператора пользовательского преобразования. Что вернёшь из оператора - того и тапки

чтобы из такого оператора вернуть shared_ptr , объект такого указателя нужно создать и вернуть из оператора.
Если такой указатель будет указывать на сам *this объект, в классе которого находится оператор, то этот самый класс этого самого *this должен быть унаследован от std::enable_shared_from_this , а в операторе будет возвращаться shared_from_this()

Но что-то мне подсказывает, что это тебе вовсе не нужно. Что-то у тебя задумано не то или делается не так
1
105 / 7 / 1
Регистрация: 27.04.2015
Сообщений: 251
21.10.2023, 12:14  [ТС]
у меня ничего не задумано, я просто разбираюсь как это работает
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
21.10.2023, 12:18
В чём смысл делать некорректные преобразования?
1
105 / 7 / 1
Регистрация: 27.04.2015
Сообщений: 251
21.10.2023, 13:45  [ТС]
прошу прощения, а в чем они не корректные?
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
21.10.2023, 16:06
Это разные классы.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12919 / 6787 / 1817
Регистрация: 18.10.2014
Сообщений: 17,169
21.10.2023, 17:04
Цитата Сообщение от Anton1978 Посмотреть сообщение
Эксперименты показывают, что вот такое компилируется и без перезагрузок конструктора и реализации operator ChadParrent()
Все это не имеет никакого отношения ни к каким "перезагрузкам конструктора и реализациям operator ChadParrent()" даже отдаленно. Поэтому не ясно, почему вы продолжаете это упоминать.

Эти функции - лишь оболочки для стандартных преобразований голых указателей. Указатели - это "встроенные" типы. Для них не существует никаких "перезагрузок" и "перегрузок". В С++ нет механизмов пользовательского влияния на преобразования указателей.

Цитата Сообщение от Anton1978 Посмотреть сообщение
но как тогда правильно привести один умный указатель одного типа к другому ?
Что значит "привести"? В С++ не разрешается просто брать и проводить что угодно к чему угодно.

Приводить указатели имеет смысл только тогда, кода фактический тип хранимого в этом месте в памяти объекта соответствует тому типу, к которому вы приводите указатель. В противном случае dynamic_cast откажется выполнять каст, а static_cast будет приводить к неопределенному поведению. То есть приводить от ChadParrent к ChadChild разрешается только если указатель изначально фактически указывает внутрь ChadChild.

У вас это требование не соблюдено. То есть ответ - никак не привести.

Добавлено через 8 минут
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Ваш код пытается выполнять преобразование ChadChild * в ChadTunyChild *. Это кросс-каст указателей. Кросс-каст указателей умеет выполнять только dynamic_cast (std::dynamic_pointer_cast), но и то только, разумеется, если целевой объект существует. В вашем случае его не существует.
Здесь мне нужно добавить уточнение: кросс-каст возможен лишь между указателями на различные базовые подобъекты в составе одного дочернего объекта. В вашем случае нет этого дочернего объекта, поэтому никакой dynamic_cast между ChadChild * в ChadTunyChild * тут тоже не возможен.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
21.10.2023, 17:04
Помогаю со студенческими работами здесь

Композиции на основе собственных типов
Здравствуйте. Пытаюсь написать реализацию простенького хештебла на основе связных цепочек для хранения дубликатов столкнулся с...

Создание собственных типов данных
Я смотрю исходники на гитхаб, там не раз можно встреть записи вида typedef int book; typedef float fl; И тому подобные записи, не...

Сортировка собственных типов данных
Задача: В соответствии с вариантом нужно реализовать шаблонную функцию (функции) для сортировки. Необходимо, чтобы разработанная...

Цвет собственных типов переменных в C++
Здрасте! Что необходимо сделать, чтобы собственные типы переменных в окне &quot;Код&quot; отображался синим цветом, а не чёрным? Вот, к...

Приведение типов собственных классов
Добрый день, пусть есть класс class Line { public int x1,x2 ; public int y1,y2 ; Line (int X1,int X2, int...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru