С Новым годом! Форум программистов, компьютерный форум, киберфорум
Наши страницы

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

Войти
Регистрация
Восстановить пароль
 
BigLow
55 / 55 / 2
Регистрация: 07.07.2013
Сообщений: 345
#1

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

17.07.2013, 15:38. Просмотров 788. Ответов 13
Метки нет (Все метки)

Пытаюсь разобраться с классами и наследованием.
Сама эта задача из Дейтела "Как программировать на 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 ? Почему не мусор? Ведь у точки нет радиуса
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.07.2013, 15:38
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Указатель на базовый класс и на производный (C++):

Есть производный класс и базовый; при чём производный использует только ЧАСТЬ ресурсов базового, правильно ли это? - C++
Ну то есть базовый класс A, с полями, допустим, a, b, c, d. И я проектирую производный класс B и я железно знаю, что он будет использовать...

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

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

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

Наследование: базовый класс Квадрат, производный класс Пирамида - C++
Помогите, пожалуйста!:cry: Добавлено через 6 минут Создать класс КВАДРАТ, член класса- длинна стороны. Предусмотреть в классе методы...

Указатели в базовом классе на базовый класс и производный класс - C++
Пишу контейнер &quot;Бинарное дерево поиска&quot; для частотного словаря. С самим контейнером особо вопросов нету. Вопрос по поводу элементов в...

13
CheshireCat
Эксперт С++
2896 / 1245 / 78
Регистрация: 27.05.2008
Сообщений: 3,405
17.07.2013, 15:50 #2
Строго говоря, второй вывод может напечатать все, что угодно. В том числе - ноль. (Ноль тоже относится к понятию "мусор".) Видимо, так звезды встали, что в той ячейке памяти оказался ноль.

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

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

Не по теме:

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

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

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

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

Не по теме:

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

0
CheshireCat
17.07.2013, 16:59
  #13

Не по теме:

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

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

0
Schizorb
510 / 462 / 16
Регистрация: 07.04.2012
Сообщений: 869
Записей в блоге: 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; // теперь в этом указателе - адрес объекта "круг"
Другое дело, как корректно вызывать методы по данному указателю. Тут могут понадобиться виртуальные функции.
1
17.07.2013, 17:19
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.07.2013, 17:19
Привет! Вот еще темы с ответами:

Создать базовый класс Тройка_чисел (Triad) и производный класс Time с полями часы, минуты и секунды - C++
Наследование. Виртуальныефункции.Полиморфизм. 1. Цельзадания: 1) Создание консольного приложения, состоящего и - Базовый класс:...

Базовый класс и производный... - C++
Есть class A. У него есть функция protected foo(); Есть класс наследник B (class B: public A). В классе-наследнике B есть функция g(),...

Базовый класс Student и производный класс Aspirant - C++
Задача была такова: Создайте класс Student, который будет содержать информацию о студенте. С помощью механизма наследования,...

Базовый класс Complex и производный класс Vector - C++
Создайте базовый класс Complex (комплексное число) для реализации комплексных чисел в алгебраической форме и основных операций с ними:...


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

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

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