Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
CEBEP
107 / 107 / 23
Регистрация: 21.03.2010
Сообщений: 445
#1

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

30.03.2014, 20:52. Просмотров 1839. Ответов 22
Метки нет (Все метки)

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 для объекта, указатель на который хранится, как указатель на А? Заранее спасибо.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.03.2014, 20:52
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Приведение к типу-наследнику (C++):

ООП. Динамическое приведение типа от родителя к наследнику
Добрый день, коллеги. Проблема в следующем. Есть два библиотечных класса...

Приведение к типу
В чем разница? static_cast&lt;int&gt;(a); и (int)a

Приведение к типу (uint8 *)
Разбирая чужой код, наткнулся на такую вот конструкцию uint8 * ...

Приведение к базовому типу
#include &lt;iostream&gt; using namespace std; class A{ public: ...

Приведение переменной к другому типу
float a = (float)x; // старый стиль float b = static_cast&lt;float&gt;(y); //...

Приведение void* указателя к типу
struct tParamStruct { const char* Result; }; tParamStruct ParamStruct; ...

22
Croessmah
++Ͻ
14160 / 8085 / 1513
Регистрация: 27.09.2012
Сообщений: 19,926
Записей в блоге: 3
Завершенные тесты: 1
30.03.2014, 21:00 #2
виртуальную функцию?
0
CEBEP
107 / 107 / 23
Регистрация: 21.03.2010
Сообщений: 445
30.03.2014, 21:39  [ТС] #3
нет, в A о ней нет никакого упоминания. функция появляется только в B
0
DrOffset
7518 / 4514 / 1097
Регистрация: 30.01.2014
Сообщений: 7,362
30.03.2014, 21:46 #4
Цитата Сообщение от CEBEP Посмотреть сообщение
нет, в A о ней нет никакого упоминания. функция появляется только в B
Это что, задание какое-то? То есть ответ должен быть в каких определенных рамках?
0
CEBEP
107 / 107 / 23
Регистрация: 21.03.2010
Сообщений: 445
30.03.2014, 21:51  [ТС] #5
нет, это проблема в реальном проекте... меня просто достало писать длиннющую конструкцию из статик-кастов, решил посоветоваться, как это сделать лучше. В правильности такой объектной архитектуры я уверен, с этой стороны пересматривать вопрос не хочу, так что просто хочется придумать более краткое, с точки зрения синтаксиса, решение
0
zss
Модератор
Эксперт С++
6956 / 6518 / 4138
Регистрация: 18.12.2011
Сообщений: 17,208
Завершенные тесты: 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;
}
Но ответственность возлагается на программиста
0
DrOffset
7518 / 4514 / 1097
Регистрация: 30.01.2014
Сообщений: 7,362
30.03.2014, 21:56 #7
Цитата Сообщение от CEBEP Посмотреть сообщение
нет, это проблема в реальном проекте...
Ну тогда напиши функцию, которая это будет делать и вызывай ее вместо кастов.
Кстати, зачем каст к void*? Лишний здесь он.

zss, reinterpret_cast тут вообще не подходит.
0
ValeryS
Модератор
7133 / 5401 / 669
Регистрация: 14.02.2011
Сообщений: 18,224
30.03.2014, 22:00 #8
Цитата Сообщение от CEBEP Посмотреть сообщение
меня просто достало писать длиннющую конструкцию из статик-кастов, решил посоветоваться, как это сделать лучше.
лучше не лучше но короче
сделай еще один указатель дочернего класса
примерно так
C++
1
2
3
 A* pointer(new B);
 B* pointerB=(B*)pointer;
pointerB->foo();
Добавлено через 2 минуты
А лучше,по моему,создавать сразу дочерний класс, а при необходимости приводить его к родительскому
0
zss
Модератор
Эксперт С++
6956 / 6518 / 4138
Регистрация: 18.12.2011
Сообщений: 17,208
Завершенные тесты: 1
30.03.2014, 22:01 #9
Цитата Сообщение от DrOffset Посмотреть сообщение
zss, reinterpret_cast тут вообще не подходит
Объясните. Компилятор обязан это проглотить!

Добавлено через 48 секунд
Цитата Сообщение от ValeryS Посмотреть сообщение
А лучше,по моему,создавать сразу дочерний класс, а при необходимости приводить его к родительскому
А автор что делает что-то другое?
0
ValeryS
Модератор
7133 / 5401 / 669
Регистрация: 14.02.2011
Сообщений: 18,224
30.03.2014, 22:04 #10
Цитата Сообщение от zss Посмотреть сообщение
А автор что делает что-то другое?
нет, создает то он наследника но тип то родителя
я имел ввиду
C++
1
 B* pointer =new B;
наследник то знает все про своего родителя и методы и члены
0
DrOffset
7518 / 4514 / 1097
Регистрация: 30.01.2014
Сообщений: 7,362
30.03.2014, 22:04 #11
Цитата Сообщение от zss Посмотреть сообщение
Объясните. Компилятор обязан это проглотить!
Это здесь непричем. reinterpret_cast говорит, что указатель типа A, теперь будет считаться указателем типа B. То есть адрес не меняется, только тип указываемого. Однако в случае наследования в общем случае нет гарантий, что адрес наследника и адрес базы будут равны. Поэтому простая реинтерпретация адреса здесь не поможет и даже вредна, т.к. приводит к неопределенному поведению. static_cast тут уместен вполне, он проведет преобразование адреса, если оно необходимо.
0
CEBEP
107 / 107 / 23
Регистрация: 21.03.2010
Сообщений: 445
30.03.2014, 22:09  [ТС] #12
Цитата Сообщение от zss Посмотреть сообщение
Объясните. Компилятор обязан это проглотить!
требование - без дополнительных вычислений. В соответствии с тем, что я знаю, приведение в стиле си может порождать reinterpret_cast, который, как и dynamic_cast, разрешается только на этапе выполнения программы. В моём проекте обращение к этим данным происходит миллионы раз, подобное приведение может ощутимо сказаться на быстродействии.
0
DrOffset
7518 / 4514 / 1097
Регистрация: 30.01.2014
Сообщений: 7,362
30.03.2014, 22:10 #13
Цитата Сообщение от CEBEP Посмотреть сообщение
порождать reinterpret_cast, который, как и dynamic_cast, разрешается только на этапе выполнения программы.
reinterpret_cast не разрешается на этапе выполнения. Но он здесь не подойдет по причинам, которые я описал в предыдущем посте.
0
zss
Модератор
Эксперт С++
6956 / 6518 / 4138
Регистрация: 18.12.2011
Сообщений: 17,208
Завершенные тесты: 1
30.03.2014, 22:11 #14
Цитата Сообщение от DrOffset Посмотреть сообщение
static_cast тут уместен вполне,
Вы абсолютно не правы.
Это как раз область ведения reinterpret_cast.
Т.е. мы выполняем действие, которое противоречит представлениям компилятора.
Он ведь не знает, что указатель показывает на экземпляр производного класса,
а мы знаем! Поэтому такое действие с точки зрения программиста оправдано.
http://ideone.com/tI2HnP
0
CEBEP
107 / 107 / 23
Регистрация: 21.03.2010
Сообщений: 445
30.03.2014, 22:17  [ТС] #15
Цитата Сообщение от ValeryS Посмотреть сообщение
А лучше,по моему,создавать сразу дочерний класс,
B является производным по отношению к A, как это показано в первом сообщении... или в виду имелось что-то другое?
0
ValeryS
Модератор
7133 / 5401 / 669
Регистрация: 14.02.2011
Сообщений: 18,224
30.03.2014, 22:20 #16
Цитата Сообщение от CEBEP Посмотреть сообщение
или в виду имелось что-то другое?
ну вот я показывал
Цитата Сообщение от ValeryS Посмотреть сообщение
B* pointer =new B;
из B то к членам A проще достучатся, чем наоборот
0
DrOffset
7518 / 4514 / 1097
Регистрация: 30.01.2014
Сообщений: 7,362
30.03.2014, 22:28 #17
Цитата Сообщение от zss Посмотреть сообщение
Вы абсолютно не правы.
Это как раз область ведения reinterpret_cast.
Т.е. мы выполняем действие, которое противоречит представлениям компилятора.
Он ведь не знает, что указатель показывает на экземпляр производного класса,
а мы знаем! Поэтому такое действие с точки зрения программиста оправдано.
Я просто оставлю это здесь.

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

Добавлено через 4 минуты
CEBEP, в чем проблема завернуть static_cast в функцию? Другого относительно безопасного способа это сделать, да еще и без дополнительных проверок, все равно нет.
1
CEBEP
107 / 107 / 23
Регистрация: 21.03.2010
Сообщений: 445
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 в функцию?
Да, это вполне адекватное решение, но тут придётся пологаться на милость компилятора в том плане, что он как может заменить вызов функции на тело так и может организовать реальный вызов функции...
0
DrOffset
7518 / 4514 / 1097
Регистрация: 30.01.2014
Сообщений: 7,362
30.03.2014, 22:37 #19
Цитата Сообщение от CEBEP Посмотреть сообщение
Да, это вполне адекватное решение, но тут придётся пологаться на милость компилятора в том плане, что он как может заменить вызов функции на тело так и может организовать реальный вызов функции...
inline однострочник практически гарантированно будет встроен любым современным компилятором.

Добавлено через 2 минуты
CEBEP, спрошу еще раз: какая необходимость делать каст через void*?
0
CEBEP
107 / 107 / 23
Регистрация: 21.03.2010
Сообщений: 445
30.03.2014, 22:37  [ТС] #20
Цитата Сообщение от DrOffset Посмотреть сообщение
Я просто оставлю это здесь.
там же речь о множественном наследовании и приведении типов к базовым. тут не имеет места ни такой вид наследования не такая ориентация приведения...
0
30.03.2014, 22:37
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.03.2014, 22:37
Привет! Вот еще темы с решениями:

Приведение указателя на void к другому типу?
в поиске смотрел - не помогло! Возникла проблемка: В книге сказано, что...

Приведение void* к типу указателя на структуру
Тема обсуждалась здесь, но решения так и нет нормального Есть два (и более,...

Приведение пользовательского типа к типу int
Написан класс DateTime и перегружены его операторы, в частности ввод/вывод в...

Приведение двух классов к типу друг друга
Всем добрый день, Прошу вашей помощи с пониманием принципов работы...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru