387 / 294 / 21
Регистрация: 07.08.2011
Сообщений: 790
Записей в блоге: 1
1

Производный класс. Перегрузка << (cout).

18.01.2012, 20:35. Показов 2914. Ответов 26
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
При инициализации массива указателей базового класса при вызове cout производный класс не отображается, отображается базовый. Без указателей все в порядке. Подскажите пожалуйста почему.
Вот пример кода:

bor.h
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
#include <iostream>
 
class Port
{
private:
    char * brand;   // название
    char * style;   // тип
    int bottles;    // бутылки
protected:
    const char * Brand() const {return brand;}
    const int Bottles() const {return bottles;} 
public:
    Port();
    Port(const char * br, const char * st, int b);
    Port(const Port & p);
    virtual~Port();
    Port & operator = (const Port & p);
    Port & operator += (int b);
    Port & operator -= (int b);
    int BottleCont()const {return bottles;}
    virtual void Show() const;
    friend std::ostream & operator<<(std::ostream & os, const Port & p);
};
 
class VintagePort : public Port
{
private:
    char * nickname;    // старый или новый
    int year;           // год
public:
    VintagePort();
    VintagePort(const char *br, int b, const char *nn, int y);
    VintagePort(const VintagePort & vp);
    ~VintagePort();
    VintagePort & operator= (const VintagePort & vp);
    void Show() const;
    friend std::ostream & operator<<(std::ostream & os, const VintagePort & vp);
};
bor.cpp
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "bor.h"
 
// методы Port
Port::Port()
{
    char *br = "none";
    brand = new char[strlen(br)+1];
    strcpy(brand,br);
    style = new char[strlen(br)+1];
    strcpy(style,br);
    bottles = 0;    
}
Port::Port(const char * br, const char * st, int b)
{
    brand = new char[strlen(br)+1];
    strcpy(brand,br);
    style = new char[strlen(st)+1];
    strcpy(style,st);
    bottles = b;    
}
Port::Port(const Port & p)
{
    brand = new char[strlen(p.brand)+1];
    strcpy(brand,p.brand);
    style = new char[strlen(p.style)+1];
    strcpy(style,p.style);
    bottles = p.bottles;
}
Port & Port::operator = (const Port & p)
{
    if(this == &p)
        return *this;
    delete [] brand;
    delete [] style;
    brand = new char[strlen(p.brand)+1];
    strcpy(brand,p.brand);
    style = new char[strlen(p.style)+1];
    strcpy(style,p.style);
    bottles = p.bottles;
 
    return *this;
}
Port & Port::operator += (int b)
{
    bottles+=b;
    return *this;
}
Port & Port::operator -= (int b)
{
    bottles-=b;
    return *this;
}
void Port::Show() const
{
    std::cout << "Brand: " << brand << std::endl;
    std::cout << "Kind: " << style << std::endl;
    std::cout << "Bottles: " << bottles;
}
std::ostream & operator<<(std::ostream & os, const Port & p)
{
    os << p.brand << ", " << p.style << ", " << p.bottles;
 
    return os;
}
 
Port::~Port() 
{
    delete [] brand; 
    delete [] style; 
}
 
// методы VintagePort
VintagePort::VintagePort():Port()
{
    nickname = new char [5];
    strcpy(nickname,"none");
    year = 0;
}
 
VintagePort::VintagePort(const char *br, int b, const char *nn, int y):Port(br,"none",b)
{
    nickname = new char[strlen(nn)+1];
    strcpy(nickname,nn);
    year = y;
}
VintagePort::VintagePort(const VintagePort & vp) : Port(vp)
{
    nickname = new char[strlen(vp.nickname)+1];
    strcpy(nickname,vp.nickname);
    year = vp.year;
}
VintagePort & VintagePort::operator= (const VintagePort & vp)
{
    if(this == &vp)
        return *this;
    Port::operator=(vp);
    delete [] nickname;
    nickname = new char[strlen(vp.nickname)+1];
    strcpy(nickname,vp.nickname);
    year = vp.year;
 
}
void VintagePort::Show() const
{
    std::cout << "Название: " << Brand() << std::endl;
    std::cout << "Kоличество бутылок: " << Bottles() << std::endl;
    std::cout << "Старое или новое: " << nickname << std::endl;
    std::cout << "Год: " << year;
}
std::ostream & operator<<(std::ostream & os, const VintagePort & vp)
{
    os << (const Port &)vp;
    os << ", " << vp.nickname << ", " << vp.year;
    return os;
}
 
VintagePort::~VintagePort() 
{
    delete [] nickname;
}
main.cpp
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
83
84
85
86
#include <iostream>
#include "bor.h"
 
const int SIZE = 2;
 
int main()
{
    setlocale (LC_ALL, "rus");
    using std::cout;
    using std::endl;
    using std::cin;
 
            char ch[40];
            char ch2[40];
            int reiting;
            int reiting2;
            int i;
 
    Port *mass [SIZE];
 
    for(i=0; i<SIZE; i++)
    {
        char letter;
        if(i!=0)
            cout << endl;
        cout << "Введите что пишем:\nPort - A, VintagePort - B, Выход - С: ";
        cin >> letter;
        if((letter<65||letter>67)&&(letter<97||letter>99))
        {i--; cin.getline(ch,40); continue;}
        cin.get();
        if(letter == 'C' || letter == 'c')
            break;
 
        switch(letter)
        {
        case 'A':
        case 'a':
            cout << "\nPort:\n";
            cout << "Введите название: ";
            cin.getline(ch,40);
            cout << "Введите тип: ";
            cin.getline(ch2,40);
            cout << "Введите количества бутылок: ";
            cin>>reiting;
 
            mass[i] = new Port(ch,ch2,reiting);
            break;
        case 'B':
        case 'b':
            cout << "\nVintagePort:\n";
            cout << "Введите название: ";
            cin.getline(ch2,40);
            cout << "Введите количество бутылок: ";
            cin >> reiting2;
            cin.get();
            cout << "Введите старый или новый: ";
            cin.getline(ch,40);
            cout << "Введите год: ";
            cin>>reiting;
 
            mass[i] = new VintagePort(ch2,reiting2,ch,reiting);
            break;
        }
    }
    
    if(i!=0)
    {
    cout << endl << endl;
    for(int i=0; i<SIZE; i++){
        mass[i]->Show();
    cout << endl << endl;
    }
 
    //cout << *(mass[0]) << endl;   // отображает Port в любом случае
 
    for(int j=0; j<SIZE; j++)
    {
        delete mass[j];
    }
    }
 
    cout << "By :)\n\n";
 
    system("pause");
    return 0;
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
18.01.2012, 20:35
Ответы с готовыми решениями:

Разработать производный от абстрактного класса Figure класс и класс, производный от производного
Разработать базовый абстрактный класс Figure с пустым виртуальным методом print для вывода в...

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

Базовый класс Complex и производный класс для реализации квадратных матриц
1) Создайте базовый класс Complex (комплексное число) для реализации комплексных чисел в...

Создать класс Point и производный класс ColoredPoint (цветная точка)
Создайте класс Point (точка на плоскости), характеризующийся двумя координатами. Создайте...

26
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
18.01.2012, 20:54 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
Введите что пишем:
Port - A, VintagePort - B, Выход - С: A
 
Port:
Введите название: qw
Введите тип: as
Введите количества бутылок: 2
 
Введите что пишем:
Port - A, VintagePort - B, Выход - С: B
 
VintagePort:
Введите название: rt
Введите количество бутылок: 6
Введите старый или новый: n
Введите год: 1234
 
 
Brand: qw
Kind: as
Bottles: 2
 
Название: rt
Kоличество бутылок: 6
Старое или новое: n
Год: 1234
 
By :)
 
Для продолжения нажмите любую клавишу . . .

Вот что я получил, правильно?
1
387 / 294 / 21
Регистрация: 07.08.2011
Сообщений: 790
Записей в блоге: 1
18.01.2012, 21:01  [ТС] 3
kravam, Да, если VintagePort попробовать вывести через cout выведен будет Port...
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
18.01.2012, 21:11 4
Вот я щас расскоментил cout
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
Введите что пишем:
Port - A, VintagePort - B, Выход - С: A
 
Port:
Введите название: Q
Введите тип: W
Введите количества бутылок: 11
 
Введите что пишем:
Port - A, VintagePort - B, Выход - С: B
 
VintagePort:
Введите название: A
Введите количество бутылок: 12
Введите старый или новый: n
Введите год: 34
 
 
Brand: Q
Kind: W
Bottles: 11
 
Название: A
Kоличество бутылок: 12
Старое или новое: n
Год: 34
 
Q, W, 11
By :)
 
Для продолжения нажмите любую клавишу . . .
А что должно быть по задумке?
1
387 / 294 / 21
Регистрация: 07.08.2011
Сообщений: 790
Записей в блоге: 1
18.01.2012, 21:17  [ТС] 5
kravam, в общем cout должен работать как Show();
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
18.01.2012, 21:26 6
Я щас буду работать, буду автоматизирвать ввод (чтоб не вводить руками каждый раз), буду убирать ввод не нужных данных (это всё ты должен был сделать, дабы код был прост), мне нужно знать что можно убрать для нахождения тык скыть ошибки, а что нельзя. Буду это делать пошагово, пока ошибка не исчезнет. Таким образом, я упрощу код, а уже в простом коде буду искать ошибку.
И каждый после очередного упрощения, мне нужно знать- исчезла ошибка или нет; для этого я буду смотреть на вывод. А каким должен быть вывод, я от тебя не могу добиться.

Каким должен быть вывод? Предлагаю остановиться на тех данных, что я ввёл. Какого вывода ты ждёшь при этих данных? Просто нарисуй и всё.
1
387 / 294 / 21
Регистрация: 07.08.2011
Сообщений: 790
Записей в блоге: 1
18.01.2012, 21:39  [ТС] 7
kravam, cout выводит в строку все данные для своего типа как Show только в строку и без подписей)
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
18.01.2012, 21:52 8
Я не знаю, что такое свой тип для cout. Для того, чтобы узнать, я должен упростить код. А чтобы упростить код правильно, мне нужно каждый раз после очередного упрощения смотреть- исчезла ошибка или нет. А для этого я должен знать, что ты ожидаешь чтобы cout выводил. И вот когда я буду знать это, я смогу упростить код, а потом уже глядя на просттой код я узнаю, что такое "свой тип для cout"

Всё упирается в то, что должен вывести cout по задумке для предлагаемых данных.
1
387 / 294 / 21
Регистрация: 07.08.2011
Сообщений: 790
Записей в блоге: 1
18.01.2012, 21:52  [ТС] 9
kravam, Вот так: )
Миниатюры
Производный класс. Перегрузка << (cout).  
0
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
18.01.2012, 22:08 10
ф-ия вывода в поток не вируальная.
чтобы вывод в поток зависил от динамического типа объекта, а не от статического, вывод тоже должен быть виртуальной ф-ией. в книжках обычно советуют поступать так:

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
class Base
{
public:
   virtual void Print(std::ostream& out) const
   {
      // тут имплемент печати базового класса
   }
};
 
class Derivated : public Base
{
public:
   virtual void Print(std::ostream& out) const
   {
      // тут имплемент печати производного класса
   }
};
 
std::ostream& operator << (std::ostream& out, const Base& base)
{
   // вот в таком случае если base ссылается на производный класс, то будет вызвана
   // ф-ия печати производного класса если она в нем переопределена.
   base.Print(out);
   return out;
}
1
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
18.01.2012, 22:19 11
KeyGen, чё-то я не понял, у тебя mass указывает на массив элементов типа Port, нулевой из которых- элемент типа Port, так ты его и получаешь по рисунку это видно. Так, а в массиве mass элемент типа VintagePort это ПЕРВЫЙ элемент. Ты хочешь получить его данные? Ну так напиши
C++
1
cout << *(mass[1]) << endl;
И всё будет круто, или я чего-то не понимаю?
0
387 / 294 / 21
Регистрация: 07.08.2011
Сообщений: 790
Записей в блоге: 1
18.01.2012, 22:24  [ТС] 12
kravam, я так и писал вывод как на картинке
C++
1
2
3
4
5
6
...
    cout << "Ввывод Port:\n";
    cout << *(mass[0]);
    cout << "\n\nВывод VintagePort:\n";
    cout << *(mass[1]) << endl;
...
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
18.01.2012, 22:50 13
Ну и всё нормально, если ты хочешь чтобы mass[0] указывал на первый элемент сделай просто


C++
1
2
3
4
5
6
7
8
9
       cout << *(mass[0]) << endl; 
        mass[0]= mass[1];
        cout << *(mass[0]) << endl;  
 
 
        for(int j=0; j<SIZE_- 1; j++)
        {
                delete mass[j];
        }
0
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
18.01.2012, 22:51 14
еще раз попробую объяснить
вот какой у вас оператор <<
C++
1
2
3
4
5
6
std::ostream & operator<<(std::ostream & os, const Port & p)
{
        os << p.brand << ", " << p.style << ", " << p.bottles;
 
        return os;
}
Это свободная ф-ия и она не вызывает никаких виртуальных методов у класса Port. Она всегда будет выводить поля просто порта, даже если p ссылается на объект VintagePort.
Т.к. у вас массив указателей на объекты типа порт, то тип выражения *mass[1] - const Port&;
Поэтому всегда будет вызываться оператор << для порта а не для винтажного порта, даже если там указатель на винтажный порт.

Если вы сделаете по примеру, который я написал выше, то у вас все заработает так, как вы хотите. Если p ссылается на винтажный порт, то позовется ф-ия печати винтажного порта (потому что она виртуальная и переопределена в винтажном порте)
1
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
18.01.2012, 23:09 15
Цитата Сообщение от DU Посмотреть сообщение
Поэтому всегда будет вызываться оператор << для порта а не для винтажного порта, даже если там указатель на винтажный порт.
Да для винтажного она вызывается, для винтажного. mass [1] указывает на винтажный порт, напишите
C++
1
         cout << *(mass[1]) << endl;
и увидите, данные винтажного порта выводятся или нет

Добавлено через 8 минут
Вот же написано:
C++
1
  mass[i] = new VintagePort(ch2,reiting2,ch,reiting);
И ходя выше задекларировано, что mass[i] указывает на Port, но происходит переопределение типа и происходит корректно, надо сказать, ибо Port- родителський класс. Так что всё просто; с этого момента mass [i] (mass[1]) указывает на винтажный порт!
0
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
18.01.2012, 23:11 16
И ходя выше задекларировано, что mass[i] указывает на Port, но происходит переопределение типа и происходит корректно, надо сказать, ибо Port- родителський класс. Так что всё просто; с этого момента mass [i] (mass[1]) указывает на винтажный порт!
да не так все. вы похоже сами проблему не понимаете.
вот упрощенный пример. соберите и посмотрите как все работает
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
#include <iostream>
 
namespace Bad
{
  class Base
  {
  };
 
  std::ostream& operator << (std::ostream& out, const Base& base)
  {
    out << "Base";
    return out;
  }
 
  class Der : public Base
  {
  };
 
  std::ostream& operator << (std::ostream& out, const Der& der)
  {
    out << "Der";
    return out;
  }
}
 
namespace Good
{
  class Base
  {
  public:
    virtual void Print(std::ostream& out) const
    {
      out << "Base";
    }
  };
 
  std::ostream& operator << (std::ostream& out, const Base& base)
  {
    base.Print(out);
    return out;
  }
 
  class Der : public Base
  {
    virtual void Print(std::ostream& out) const
    {
      out << "Der";
    }
  };
}
 
int main()
{
  {
    // Base ссылается на производный класс (считай винтажный порт.)
    // Но вызывается оператор, который определен для базового класса (считай обычный порт)
    std::cout << "Bad:" << std::endl;
    Bad::Der der;
    Bad::Base* base = &der;
    std::cout << "print: " << *base << std::endl;
  }
 
  {
    // А вот по прежнему вызывается оператор, который определен для базового класса
    // (другого даже нет), но работает все так, как и задумывалось.
    std::cout << "Good:" << std::endl;
    Good::Der der;
    Good::Base* base = &der;
    std::cout << "print: " << *base << std::endl;
  }
 
  return 0;
}
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
18.01.2012, 23:15 17
А на пальцах? Я пойму...
А вообще если челу надо, чтобы переменная имела значение X, надо ей это значение присвоить а не простыни выкладывать.
0
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
18.01.2012, 23:22 18
два раза на пальцах объяснил и один раз на примере, что лучше чем пальцы. Если проблемы с пониманием того, как компилятор подбирает ф-ии для вызова - то тут лучше соответствующий материал поизучать (без обид). Еще раз на пример посмотрите. А лучше откомпилируйте и посмотрите, что выводится.
0
Жарю без масла
867 / 749 / 225
Регистрация: 13.01.2012
Сообщений: 1,702
18.01.2012, 23:23 19
Цитата Сообщение от kravam Посмотреть сообщение
Да для винтажного она вызывается, для винтажного. mass [1] указывает на винтажный порт
этого нет и быть не может, потому что operator>> не является виртуальной ф-ей-членом класса Port.
перегрузка ф-ии (а именно она здесь) осуществляется по статическим типам на этапе компиляции. и на этапе же компиляции генерируется код для вызова
C++
1
std::ostream & operator<<(std::ostream & os, const Port & p)
и компилятору нас*ать, каким будет на самом деле динамический тип параметра во время выполнения
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
18.01.2012, 23:25 20
Как можно сделать, я знаю, просто мне кажется мой способ более простой, чем ваш. Давайте поговорим тезисно.

1) По окончанию ввода mass[0] указывает на Port, а mass [1] на элемент типа VintagePort
Согласны?
0
18.01.2012, 23:25
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
18.01.2012, 23:25
Помогаю со студенческими работами здесь

Разработать класс Tableware (посуда) и производный класс Dish (тарелка). Описать атрибуты
Разработать класс Tableware (посуда) и производный класс Dish (тарелка). Описать атрибуты.

Разработать класс Man (человек) и производный класс Student (студент). Описать атрибуты.
Разработать класс Man (человек) и производный класс Student (студент). Описать атрибуты.

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

Реализовать класс Pair (пара чисел); определить производный класс Complex (комплексное число)
Здравствуйте. Задали задание: Создать класс Pair (пара чисел); определить метод перемножения...

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

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


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru