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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
ZiminAS1990
2 / 2 / 0
Регистрация: 27.07.2012
Сообщений: 31
#1

Тонкость с указателями - взятие указателя на базовый класс - C++

13.12.2012, 19:53. Просмотров 418. Ответов 7
Метки нет (Все метки)

Как-то возник в голове вопрос:
пусть класс D наследует классы A и B. Если у меня есть объект D, я беру его адрес и типизирую его к базовым классам A и B. Получаю два указателя типа A* и B*. Будут ли они указывать на корректные объекты?

Я всегда предполагал, что конструкции типа:
Type1 *a = (Type1*)b;
это указания компилятору интерпретировать данные по указателю b как данные типа Type1. А значит, указатель "a" всегда должен указывать на ту же ячейку памяти что и указатель b.
Если так, то указатели A* и B* должны будут указывать на одну и ту же ячейку памяти, что приведёт к ошибке (это ведь должно быть два разных объекта!)

Решил проверить. Написал простую программу:
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
class A {
public:
A() : a(10), b(20) {}
double a;
double b;
};
 
class B {
public:
B() : c(30), d(40) {}
double c;
double d;
};
 
class D : public A, public B {
public:
D() : e(50), j(60) {}
double e;
double j;
};
 
int main()
{
D objD;
// Получим базовые классы от производного:
A *objA = (A*)&objD;
B *objB = (B*)&objD;
// Получим производный класс от базового:
D* objDFromA = (D*)objA;
D* objDFromB = (D*)objB;
objD.a = 100;
objD.c = 300;
return 0;
}
Получилось так, что указатели objA и objB указывают на РАЗНЫЕ ячейки памяти, не смотря на то, что они получены простой типизацией одного и того же указателя objD.
Как реализован этот механизм? Получается, что вычисление значений указателей objA и objB производится в процессе выполнения программы (для этого генерируются отдельные инструкции в исполняемом файле)?
Это стандартный трюк и его можно безбоязненно использовать? Или не все компиляторы это поддерживают? (я использовал g++)
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.12.2012, 19:53
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Тонкость с указателями - взятие указателя на базовый класс (C++):

typeid определяет тип указателя на базовый класс, как тип "базовый класс". Вне зависимости от присвоенного ему значения - C++
Вот код: #include <iostream> #include <string> #include <conio.h> #include <windows.h> #include <typeinfo> using...

Написать базовый класс с двумя полями, которые являются указателями на int - C++
Опишите базовый класс в котором есть хотя бы 1 чисто виртуальный метод. Опишите класс наследник базового класса. Внутри main должно быть...

Как при помощи указателя на базовый класс обратится к полю наследуемого класса? - C++
Всем привет! столкнулся с такой проблемой. У меня есть массив указателей на базовый виртуальный класс,и например я присваиваю указателю на...

Написать обработчик исключений ситуации при преобразовании указателя на класс B до указателя на абстрактный класс А ... - C++
Написать обработчик исключений ситуации при преобразовании указателя на класс B до указателя на абстрактный класс А ... как сделать...

Как сделать функцию от указателя на класс и указателя на метод? - C++
Не получается сделать функцию, параметрами которой являются указатель на класс и на метод. Обращаться к классу нужно именно по указателю,...

Класс: как обратиться к методу производного класса через итератор на базовый класс? - C++
Есть абстрактный и два порожденных. Хочу создать например list<Base*> list1; затем добавляю себе в список: ...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
soon
2540 / 1305 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
13.12.2012, 21:38 #2
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
#include <iostream>
 
struct Foo
{
    virtual ~Foo()
    {
 
    }
};
 
struct Bar
{
    virtual ~Bar()
    {
 
    }
};
 
struct Baz: public Foo, public Bar
{
 
};
 
int main()
{
    Baz baz;
 
    auto foo_dynamic = dynamic_cast<Foo*>(&baz);
    auto bar_dynamic = dynamic_cast<Bar*>(&baz);
 
    std::cout << foo_dynamic << ' ' << bar_dynamic << std::endl;
 
    auto foo_reinterpret = reinterpret_cast<Foo*>(&baz);
    auto bar_reinterpret = reinterpret_cast<Bar*>(&baz);
 
    std::cout << foo_reinterpret << ' ' << bar_reinterpret << std::endl;
 
    return 0;
}
Не используйте в плюсах приведение в стиле Си.
1
ZiminAS1990
2 / 2 / 0
Регистрация: 27.07.2012
Сообщений: 31
14.12.2012, 10:07  [ТС] #3
Спасибо!
Нужно будет по разбираться с этим
0
WhiteP
606 / 204 / 23
Регистрация: 20.11.2012
Сообщений: 426
14.12.2012, 11:06 #4
Почитай - хорошая статья в тему:
http://devdoc.web-ide.ru/index.php/c...rtual_base.htm
1
vxg
Модератор
3162 / 1965 / 220
Регистрация: 13.01.2012
Сообщений: 7,523
14.12.2012, 16:42 #5
Цитата Сообщение от soon Посмотреть сообщение
Не используйте в плюсах приведение в стиле Си
...или думайте что делаете. ничто не мешает использовать стиль Си.
0
soon
2540 / 1305 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
14.12.2012, 18:00 #6
Цитата Сообщение от vxg Посмотреть сообщение
ничто не мешает использовать стиль Си.
Кастование в стиле C++ вносит определенную ясность. Да и смешивать два языка не есть хорошо.
0
yekka
385 / 149 / 8
Регистрация: 12.05.2011
Сообщений: 450
14.12.2012, 19:58 #7
очевидно, что при множественном наследовании два объекта-предка не могут иметь один и тот же адрес, поэтому для преобразования указателя на дочерний объект к указателю на второй родительский объект (и обратно) к указателю необходимо будет добавить некоторое смещение.

Вообще, сишное приведение типов сначала пытается применить static_cast, а если не получается, то использует reinterpret_cast. В твоем случае, очевидно, достаточно static_cast'а, поэтому преобразование будет "умным" (т.е. с добавлением нужного смещения при необходимости). А если явно запросить reinterpret_cast, то смещение добавлено не будет и в общем случае получим нерабочий указатель.
1
ZiminAS1990
2 / 2 / 0
Регистрация: 27.07.2012
Сообщений: 31
14.12.2012, 20:53  [ТС] #8
Цитата Сообщение от WhiteP Посмотреть сообщение
Почитай - хорошая статья в тему:
http://devdoc.web-ide.ru/index.php/c...rtual_base.htm
О! Спасибо большое! Низкоуровневые вещи - это как раз то, что чаще всего вносит полную ясность без лишних абстракций.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.12.2012, 20:53
Привет! Вот еще темы с ответами:

Создать базовый класс Car (машина) и производный класс Lorry (грузовик): ООП ошибки - C++
Создать базовый класс Car (машина), характеризуемый торговой маркой (строка), числом цилиндров, мощностью. Определить методы переназначения...

Класс: Создать абстрактный базовый класс Figure с виртуальными методами вычисления площади и периметра. - C++
Создать абстрактный базовый класс Figure с виртуальными методами вычисления площади и периметра. Создать производные классы: Rectangle...

Создать базовый класс - Array и производный класс - Money для работы денежной суммы - C++
ПОМОГИТЕ, ПОЖАЛУЙСТА, С ЗАДАЧЕЙ Создать базовый класс - Array и производный класс - Money для работы денежной суммы

Создать базовый класс Triad и производный класс vector3D - C++
Помогите пожалуйста с заданием. Часть кода(vector3D) сделал, вроде работает Нужно помочь с классом Triad. Вот полное задание: ...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
14.12.2012, 20:53
Ответ Создать тему
Опции темы

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