Форум программистов, компьютерный форум CyberForum.ru

Приведение к типу-наследнику - C++

Восстановить пароль Регистрация
 
 
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
30.03.2014, 20:52     Приведение к типу-наследнику #1
C++
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
class A {
};
class B: public A {
    void foo() const { std::cout << "some is king of every fish"; }
};
int main() {
    A* pointer(new B);
    static_cast<B*>(static_cast<void*>(pointer))->foo();
    return 0;
}
Можите на пальцах объяснить, как, без каких бы то ни было проверок, без дополнительных вычислений на этапе выполнения вызвать метод foo класса B для объекта, указатель на который хранится, как указатель на А? Заранее спасибо.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.03.2014, 20:52     Приведение к типу-наследнику
Посмотрите здесь:

C++ Приведение указателя на void к другому типу?
что происходит со старым конструктором когда я создаю новый, пренадлежащий производному типу? (первый конструктор пренадлежит базовому типу) C++
C++ Приведение void указателя к определенному типу с сохранением результата
C++ Приведение void* к типу указателя на структуру
Приведение void* указателя к типу C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11824 / 6803 / 769
Регистрация: 27.09.2012
Сообщений: 16,871
Записей в блоге: 2
Завершенные тесты: 1
30.03.2014, 21:00     Приведение к типу-наследнику #2
виртуальную функцию?
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
30.03.2014, 21:39  [ТС]     Приведение к типу-наследнику #3
нет, в A о ней нет никакого упоминания. функция появляется только в B
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
30.03.2014, 21:46     Приведение к типу-наследнику #4
Цитата Сообщение от CEBEP Посмотреть сообщение
нет, в A о ней нет никакого упоминания. функция появляется только в B
Это что, задание какое-то? То есть ответ должен быть в каких определенных рамках?
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
30.03.2014, 21:51  [ТС]     Приведение к типу-наследнику #5
нет, это проблема в реальном проекте... меня просто достало писать длиннющую конструкцию из статик-кастов, решил посоветоваться, как это сделать лучше. В правильности такой объектной архитектуры я уверен, с этой стороны пересматривать вопрос не хочу, так что просто хочется придумать более краткое, с точки зрения синтаксиса, решение
zss
Модератор
Эксперт С++
 Аватар для zss
5943 / 5548 / 1783
Регистрация: 18.12.2011
Сообщений: 14,171
Завершенные тесты: 1
30.03.2014, 21:51     Приведение к типу-наследнику #6
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
class A {
};
class B:public A 
{
public:
    void foo() const { std::cout << "some is king of every fish"; }
};
int main() {
    A* pointer=new B;
    reinterpret_cast<B*>(pointer)->foo();
    return 0;
}
Но ответственность возлагается на программиста
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
30.03.2014, 21:56     Приведение к типу-наследнику #7
Цитата Сообщение от CEBEP Посмотреть сообщение
нет, это проблема в реальном проекте...
Ну тогда напиши функцию, которая это будет делать и вызывай ее вместо кастов.
Кстати, зачем каст к void*? Лишний здесь он.

zss, reinterpret_cast тут вообще не подходит.
ValeryS
Модератор
6376 / 4842 / 442
Регистрация: 14.02.2011
Сообщений: 16,045
30.03.2014, 22:00     Приведение к типу-наследнику #8
Цитата Сообщение от CEBEP Посмотреть сообщение
меня просто достало писать длиннющую конструкцию из статик-кастов, решил посоветоваться, как это сделать лучше.
лучше не лучше но короче
сделай еще один указатель дочернего класса
примерно так
C++
1
2
3
 A* pointer(new B);
 B* pointerB=(B*)pointer;
pointerB->foo();
Добавлено через 2 минуты
А лучше,по моему,создавать сразу дочерний класс, а при необходимости приводить его к родительскому
zss
Модератор
Эксперт С++
 Аватар для zss
5943 / 5548 / 1783
Регистрация: 18.12.2011
Сообщений: 14,171
Завершенные тесты: 1
30.03.2014, 22:01     Приведение к типу-наследнику #9
Цитата Сообщение от DrOffset Посмотреть сообщение
zss, reinterpret_cast тут вообще не подходит
Объясните. Компилятор обязан это проглотить!

Добавлено через 48 секунд
Цитата Сообщение от ValeryS Посмотреть сообщение
А лучше,по моему,создавать сразу дочерний класс, а при необходимости приводить его к родительскому
А автор что делает что-то другое?
ValeryS
Модератор
6376 / 4842 / 442
Регистрация: 14.02.2011
Сообщений: 16,045
30.03.2014, 22:04     Приведение к типу-наследнику #10
Цитата Сообщение от zss Посмотреть сообщение
А автор что делает что-то другое?
нет, создает то он наследника но тип то родителя
я имел ввиду
C++
1
 B* pointer =new B;
наследник то знает все про своего родителя и методы и члены
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
30.03.2014, 22:04     Приведение к типу-наследнику #11
Цитата Сообщение от zss Посмотреть сообщение
Объясните. Компилятор обязан это проглотить!
Это здесь непричем. reinterpret_cast говорит, что указатель типа A, теперь будет считаться указателем типа B. То есть адрес не меняется, только тип указываемого. Однако в случае наследования в общем случае нет гарантий, что адрес наследника и адрес базы будут равны. Поэтому простая реинтерпретация адреса здесь не поможет и даже вредна, т.к. приводит к неопределенному поведению. static_cast тут уместен вполне, он проведет преобразование адреса, если оно необходимо.
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
30.03.2014, 22:09  [ТС]     Приведение к типу-наследнику #12
Цитата Сообщение от zss Посмотреть сообщение
Объясните. Компилятор обязан это проглотить!
требование - без дополнительных вычислений. В соответствии с тем, что я знаю, приведение в стиле си может порождать reinterpret_cast, который, как и dynamic_cast, разрешается только на этапе выполнения программы. В моём проекте обращение к этим данным происходит миллионы раз, подобное приведение может ощутимо сказаться на быстродействии.
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
30.03.2014, 22:10     Приведение к типу-наследнику #13
Цитата Сообщение от CEBEP Посмотреть сообщение
порождать reinterpret_cast, который, как и dynamic_cast, разрешается только на этапе выполнения программы.
reinterpret_cast не разрешается на этапе выполнения. Но он здесь не подойдет по причинам, которые я описал в предыдущем посте.
zss
Модератор
Эксперт С++
 Аватар для zss
5943 / 5548 / 1783
Регистрация: 18.12.2011
Сообщений: 14,171
Завершенные тесты: 1
30.03.2014, 22:11     Приведение к типу-наследнику #14
Цитата Сообщение от DrOffset Посмотреть сообщение
static_cast тут уместен вполне,
Вы абсолютно не правы.
Это как раз область ведения reinterpret_cast.
Т.е. мы выполняем действие, которое противоречит представлениям компилятора.
Он ведь не знает, что указатель показывает на экземпляр производного класса,
а мы знаем! Поэтому такое действие с точки зрения программиста оправдано.
http://ideone.com/tI2HnP
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
30.03.2014, 22:17  [ТС]     Приведение к типу-наследнику #15
Цитата Сообщение от ValeryS Посмотреть сообщение
А лучше,по моему,создавать сразу дочерний класс,
B является производным по отношению к A, как это показано в первом сообщении... или в виду имелось что-то другое?
ValeryS
Модератор
6376 / 4842 / 442
Регистрация: 14.02.2011
Сообщений: 16,045
30.03.2014, 22:20     Приведение к типу-наследнику #16
Цитата Сообщение от CEBEP Посмотреть сообщение
или в виду имелось что-то другое?
ну вот я показывал
Цитата Сообщение от ValeryS Посмотреть сообщение
B* pointer =new B;
из B то к членам A проще достучатся, чем наоборот
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
30.03.2014, 22:28     Приведение к типу-наследнику #17
Цитата Сообщение от zss Посмотреть сообщение
Вы абсолютно не правы.
Это как раз область ведения reinterpret_cast.
Т.е. мы выполняем действие, которое противоречит представлениям компилятора.
Он ведь не знает, что указатель показывает на экземпляр производного класса,
а мы знаем! Поэтому такое действие с точки зрения программиста оправдано.
Я просто оставлю это здесь.

Цитата Сообщение от zss Посмотреть сообщение
В этом конкретном примере это работает. Однако я говорил про общий случай и про возможные последствия. Мы не знаем наверняка насколько сложная иерархия у ТС в проекте и какие будут в будущем use cases.

Добавлено через 4 минуты
CEBEP, в чем проблема завернуть static_cast в функцию? Другого относительно безопасного способа это сделать, да еще и без дополнительных проверок, все равно нет.
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
30.03.2014, 22:31  [ТС]     Приведение к типу-наследнику #18
Цитата Сообщение от ValeryS Посмотреть сообщение
ну вот я показывал
нашел. Да, в некоторых местах так делать удаётся, но синтаксически ещё более накладно... если вводить много вспомогательных строчек, код становится ещё менее читаемый чем при громоздких однострочных выражениях:
C++
1
2
3
4
5
6
7
8
9
void Renumbering::splitSideTest(size_t i) {
    VertexData::SplitSide s(static_cast<VertexData*>(static_cast<void*>(data.nodeData(i)))->getSide());
    for (Graph::NodeItem::const_iterator it(data.nodeItem(i).begin()), end(data.nodeItem(i).end()); it != end; ++it) {
        if (static_cast<VertexData*>(static_cast<void*>(data.nodeData(it->first)))->getSide() != s) {
            static_cast<VertexData*>(static_cast<void*>(data.nodeData(i)))->setSide(VertexData::Splitter);
            return;
        }
    }
}
вот пример такого завала... замечу, что во всех трёх случаях аргументами кастов являются разные величины, т. е. понадобилось бы три вспомогательных строки типа VertexData* pointer = (VertexData*) data.nodeData(i); которые сами по себе уже нагоняют тоску...

Добавлено через 2 минуты
Цитата Сообщение от DrOffset Посмотреть сообщение
в чем проблема завернуть static_cast в функцию?
Да, это вполне адекватное решение, но тут придётся пологаться на милость компилятора в том плане, что он как может заменить вызов функции на тело так и может организовать реальный вызов функции...
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
30.03.2014, 22:37     Приведение к типу-наследнику #19
Цитата Сообщение от CEBEP Посмотреть сообщение
Да, это вполне адекватное решение, но тут придётся пологаться на милость компилятора в том плане, что он как может заменить вызов функции на тело так и может организовать реальный вызов функции...
inline однострочник практически гарантированно будет встроен любым современным компилятором.

Добавлено через 2 минуты
CEBEP, спрошу еще раз: какая необходимость делать каст через void*?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.03.2014, 22:37     Приведение к типу-наследнику
Еще ссылки по теме:

C++ приведение переменной к другому типу
Приведение любого двумерного массива к типу указатель на указатель C++
C++ Выражение должно относиться к целочисленному типу или типу перечисления без области видимости

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

Или воспользуйтесь поиском по форуму:
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
30.03.2014, 22:37  [ТС]     Приведение к типу-наследнику #20
Цитата Сообщение от DrOffset Посмотреть сообщение
Я просто оставлю это здесь.
там же речь о множественном наследовании и приведении типов к базовым. тут не имеет места ни такой вид наследования не такая ориентация приведения...
Yandex
Объявления
30.03.2014, 22:37     Приведение к типу-наследнику
Ответ Создать тему
Опции темы

Текущее время: 13:35. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru