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

Указатель на базовый класс и на производный - C++

Восстановить пароль Регистрация
 
BigLow
55 / 55 / 2
Регистрация: 07.07.2013
Сообщений: 345
17.07.2013, 15:38     Указатель на базовый класс и на производный #1
Пытаюсь разобраться с классами и наследованием.
Сама эта задача из Дейтела "Как программировать на C++"
Есть базовый класс Точка и у него один наследник Круг. В самой программе определяю две переменных у два указателя на эти классы.

Вообщем, если указателю на производный класс присвоить указатель на базовый, то странный вывод. Печатает что радиус равен 0 (я в комментарии показал вывод программы)

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "iostream"
#include "iomanip"
 
class CPoint
{
    friend std::ostream &operator<<(std::ostream &out, const CPoint &point);
 
public:
    CPoint(double x=0.0, double y=0.0);
    void SetPoint(double x, double y);
 
protected:
    double mX, mY;
};
 
class CCircle : public CPoint
{
    friend std::ostream &operator<<(std::ostream &out, const CCircle &circle);
 
public:
    CCircle(double x=0.0, double y=0.0, double radius=1.0);
    void SetRadius(double radius);
 
protected:
    double mRadius;
};
 
 
 
 
 // CPoint
CPoint::CPoint(double x, double y)          { SetPoint(x, y); }
 
void CPoint::SetPoint(double x, double y)   { mX=x;  mY=y; }
 
std::ostream &operator<<(std::ostream &out, const CPoint &point)
{
    std::streamsize prec = std::cout.precision();
    out << "[" << std::fixed << std::setprecision(2) << point.mX << ", " << point.mY << "]" << std::setprecision(prec);
    return out;
}
 
 
 
 
 
// CCircle
CCircle::CCircle(double x, double y, double radius)
    : CPoint(x, y)
{
    SetRadius(radius);
}
 
void CCircle::SetRadius(double radius)          { mRadius=(radius>0.0) ? radius : 1.0; }
 
std::ostream &operator<<(std::ostream &out, const CCircle &circle)
{
    std::streamsize prec = std::cout.precision();
    out << "Центр = [" << std::fixed << std::setprecision(2) << circle.mX << ", " << circle.mY << "]; Радиус = " << circle.mRadius << std::setprecision(prec);
    return out;
}
 
 
 
 
 
 
int main()
{
    setlocale(LC_ALL, "Russian");
 
    CPoint      point(1.1, 2.2),  *ptrPoint;
    CCircle     circle(5.5, 6.6, 10.0),  *ptrCircle;
 
    ptrPoint=&point;
    ptrCircle=(CCircle *)ptrPoint;
    std::cout << "*ptrPoint:  " << *ptrPoint << std::endl;      // *ptrPoint:  [1.10, 2.20]
    std::cout << "*ptrCircle: " << *ptrCircle << std::endl;     // *ptrCircle: Центр = [1.10, 2.20]; Радиус = 0.00
 
    system("pause");
    return 0;
}

Почему второй вывод печатает Радиус = 0.00 ? Почему не мусор? Ведь у точки нет радиуса
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.07.2013, 15:38     Указатель на базовый класс и на производный
Посмотрите здесь:

Базовый класс и производный... C++
Есть производный класс и базовый; при чём производный использует только ЧАСТЬ ресурсов базового, правильно ли это? C++
Есть базовый и производный класс, в базовом определена функция, необходимо её объявить в производном! C++
Создать базовый класс Points и производный от него Line C++
Указатели в базовом классе на базовый класс и производный класс C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
CheshireCat
Эксперт С++
2907 / 1235 / 78
Регистрация: 27.05.2008
Сообщений: 3,307
17.07.2013, 15:50     Указатель на базовый класс и на производный #2
Строго говоря, второй вывод может напечатать все, что угодно. В том числе - ноль. (Ноль тоже относится к понятию "мусор".) Видимо, так звезды встали, что в той ячейке памяти оказался ноль.

"с хабаром вернулся - чудо, живой вернулся - удача, патрульная пуля мимо - везенье, а все остальное - судьба..." (с)
Ilot
Модератор
Эксперт С++
1765 / 1140 / 221
Регистрация: 16.05.2013
Сообщений: 3,017
Записей в блоге: 5
Завершенные тесты: 1
17.07.2013, 15:59     Указатель на базовый класс и на производный #3
BigLow, тебя эта строчка не смущает?
C++
1
    ptrCircle=(CCircle *)ptrPoint;
Сделай так:
C++
1
    ptrCircle=&circle;
BigLow
55 / 55 / 2
Регистрация: 07.07.2013
Сообщений: 345
17.07.2013, 16:04  [ТС]     Указатель на базовый класс и на производный #4
Цитата Сообщение от Ilot Посмотреть сообщение
Сделай так:
C++
1
ptrCircle=&circle;
там смысл в том, что круг рассматривается как точка

конечно получается непонятно что, но это чтобы лучше понять наследование
CheshireCat
Эксперт С++
2907 / 1235 / 78
Регистрация: 27.05.2008
Сообщений: 3,307
17.07.2013, 16:09     Указатель на базовый класс и на производный #5
Наоборот: точка (ptrPoint) рассматривается как круг (ptrCircle).

Не по теме:

Я бы высказался в том смысле, что Дейтел тут свалял дурака. Отношение наследования реализует отношение "является": объект класса-потомка является одновременно и объектом класса-предка, и поэтому может быть подставлен во всех случаях, когда по логике программы требуется объект класса-предка (LSP). Круг же не является точкой.

BigLow
55 / 55 / 2
Регистрация: 07.07.2013
Сообщений: 345
17.07.2013, 16:11  [ТС]     Указатель на базовый класс и на производный #6
Цитата Сообщение от CheshireCat Посмотреть сообщение
Ноль тоже относится к понятию "мусор".
теперь буду знать. обычно когда переменная содержит мусор, то при выводе показывает огромное положительное или отрицательное число

Добавлено через 1 минуту
Цитата Сообщение от CheshireCat Посмотреть сообщение
Наоборот: точка (ptrPoint) рассматривается как круг (ptrCircle)
да у меня от этого уже голова кругом
CheshireCat
Эксперт С++
2907 / 1235 / 78
Регистрация: 27.05.2008
Сообщений: 3,307
17.07.2013, 16:13     Указатель на базовый класс и на производный #7
Не совсем так. "Мусор" может показать что угодно - "огромное" положительное или отрицательное число, или "не очень огромное", или "совсем малюсенькое", или ноль... вообще - что угодно. В прямом смысле слова. Ноль тоже подходит под критерий "что угодно". :-)
Ilot
Модератор
Эксперт С++
1765 / 1140 / 221
Регистрация: 16.05.2013
Сообщений: 3,017
Записей в блоге: 5
Завершенные тесты: 1
17.07.2013, 16:16     Указатель на базовый класс и на производный #8
там смысл в том, что круг рассматривается как точка
А понятно. Что то я сразу не сообразил.
Ответ на вопрос может стоит поискать в самом компиляторе. Возможно он при приведении типов автоматически обнуляет свободные поля?

Проверил: добовил еще одно поле в класс Circle/Та же басня - значение нуль. Значит действительно компилятор при приведении типов обнуляет свободные поля.
CheshireCat
Эксперт С++
2907 / 1235 / 78
Регистрация: 27.05.2008
Сообщений: 3,307
17.07.2013, 16:21     Указатель на базовый класс и на производный #9
Нет, он ничего не "обнуляет". Просто - совпадение.....
Кстати, компиль какой? и как транслируешь - в debugили в release ?
BigLow
55 / 55 / 2
Регистрация: 07.07.2013
Сообщений: 345
17.07.2013, 16:23  [ТС]     Указатель на базовый класс и на производный #10
я в debug транслирую
visual studio 2010
zer0mail
2178 / 1861 / 187
Регистрация: 03.07.2012
Сообщений: 6,623
Записей в блоге: 1
17.07.2013, 16:35     Указатель на базовый класс и на производный #11
Да ничего он не обнуляет. Нельзя приводить тип родителя к типу наследника - в полях наследника будет мусор.
Мимино
17.07.2013, 16:46
  #12

Не по теме:

Цитата Сообщение от CheshireCat Посмотреть сообщение
Не по теме:
Я бы высказался в том смысле, что Дейтел тут свалял дурака. Отношение наследования реализует отношение "является": объект класса-потомка является одновременно и объектом класса-предка, и поэтому может быть подставлен во всех случаях, когда по логике программы требуется объект класса-предка (LSP). Круг же не является точкой.
Пример не очень удачный, т.к. сложный для понимания, но тем не менее правильный. Круг на плоскости можно представить как точку центра окружности и радиуса (как в примере). Этого достаточно, чтобы вычислить любую точку на окружности. Получается, что по его примеру круг является точкой(началом координат отрезка "радиус") + длина радиуса.
А вот следующие примеры с наследником класса Circle - класс Cylindr, который определяется еще и высотой, действительно лажа выходит, т.к. у точки нет z-координаты. Это справедливо только если центры оснований цилиндра лежат в плоскости (x, y)

CheshireCat
17.07.2013, 16:59
  #13

Не по теме:

Цитата Сообщение от Мимино Посмотреть сообщение
Круг на плоскости можно представить как точку центра окружности и радиуса (как в примере). Этого достаточно, чтобы вычислить любую точку на окружности. Получается, что по его примеру круг является точкой(началом координат отрезка "радиус") + длина радиуса.
Ннуууу..... мне, конечно, кажется, что это объяснение "притянуто за уши" (то, что называется "подгонка результата под ответ"), но - ладно, допускаю возможность и такого толкования... Хотя кмк здесь мы имеем в чистом виде отношение агрегирования "включает": круг включает (содержит в себе) точку центра и радиус.

Короче, к этим надуманным примерам в книжках от Дейтела/Шилдта/etc. надо относиться изрядно критически.

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.07.2013, 17:19     Указатель на базовый класс и на производный
Еще ссылки по теме:

Иерархия классов и указатель на базовый класс C++
C++ Виртуальное наследование (указатель на базовый класс)
C++ Разработать производный от абстрактного класса Figure класс и класс, производный от производного

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

Или воспользуйтесь поиском по форуму:
Schizorb
 Аватар для Schizorb
508 / 460 / 16
Регистрация: 07.04.2012
Сообщений: 865
Записей в блоге: 1
Завершенные тесты: 1
17.07.2013, 17:19     Указатель на базовый класс и на производный #14
Цитата Сообщение от BigLow Посмотреть сообщение
если указателю на производный класс присвоить указатель на базовый
Так не стоит делать. Наоборот, без проблем указателю на базовый класс можно присвоить адрес объекта производного класса. То есть, если круг наследуется от точки:

C++
1
2
3
4
5
6
7
CPoint      point(1.1, 2.2);
CCircle     circle(5.5, 6.6, 10.0);
 
CPoint * ptrPoint;
    
ptrPoint = &point; // в указателе - адрес объекта "точка"
ptrPoint = &circle; // теперь в этом указателе - адрес объекта "круг"
Другое дело, как корректно вызывать методы по данному указателю. Тут могут понадобиться виртуальные функции.
Yandex
Объявления
17.07.2013, 17:19     Указатель на базовый класс и на производный
Ответ Создать тему
Опции темы

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