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

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

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 14, средняя оценка - 4.86
KeyGen
 Аватар для KeyGen
333 / 289 / 6
Регистрация: 07.08.2011
Сообщений: 789
Записей в блоге: 1
18.01.2012, 20:35     Производный класс. Перегрузка << (cout). #1
При инициализации массива указателей базового класса при вызове 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;
}
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
18.01.2012, 20:54     Производный класс. Перегрузка << (cout). #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 :)
 
Для продолжения нажмите любую клавишу . . .

Вот что я получил, правильно?
KeyGen
 Аватар для KeyGen
333 / 289 / 6
Регистрация: 07.08.2011
Сообщений: 789
Записей в блоге: 1
18.01.2012, 21:01  [ТС]     Производный класс. Перегрузка << (cout). #3
kravam, Да, если VintagePort попробовать вывести через cout выведен будет Port...
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
18.01.2012, 21:11     Производный класс. Перегрузка << (cout). #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 :)
 
Для продолжения нажмите любую клавишу . . .
А что должно быть по задумке?
KeyGen
 Аватар для KeyGen
333 / 289 / 6
Регистрация: 07.08.2011
Сообщений: 789
Записей в блоге: 1
18.01.2012, 21:17  [ТС]     Производный класс. Перегрузка << (cout). #5
kravam, в общем cout должен работать как Show();
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
18.01.2012, 21:26     Производный класс. Перегрузка << (cout). #6
Я щас буду работать, буду автоматизирвать ввод (чтоб не вводить руками каждый раз), буду убирать ввод не нужных данных (это всё ты должен был сделать, дабы код был прост), мне нужно знать что можно убрать для нахождения тык скыть ошибки, а что нельзя. Буду это делать пошагово, пока ошибка не исчезнет. Таким образом, я упрощу код, а уже в простом коде буду искать ошибку.
И каждый после очередного упрощения, мне нужно знать- исчезла ошибка или нет; для этого я буду смотреть на вывод. А каким должен быть вывод, я от тебя не могу добиться.

Каким должен быть вывод? Предлагаю остановиться на тех данных, что я ввёл. Какого вывода ты ждёшь при этих данных? Просто нарисуй и всё.
KeyGen
 Аватар для KeyGen
333 / 289 / 6
Регистрация: 07.08.2011
Сообщений: 789
Записей в блоге: 1
18.01.2012, 21:39  [ТС]     Производный класс. Перегрузка << (cout). #7
kravam, cout выводит в строку все данные для своего типа как Show только в строку и без подписей)
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
18.01.2012, 21:52     Производный класс. Перегрузка << (cout). #8
Я не знаю, что такое свой тип для cout. Для того, чтобы узнать, я должен упростить код. А чтобы упростить код правильно, мне нужно каждый раз после очередного упрощения смотреть- исчезла ошибка или нет. А для этого я должен знать, что ты ожидаешь чтобы cout выводил. И вот когда я буду знать это, я смогу упростить код, а потом уже глядя на просттой код я узнаю, что такое "свой тип для cout"

Всё упирается в то, что должен вывести cout по задумке для предлагаемых данных.
KeyGen
 Аватар для KeyGen
333 / 289 / 6
Регистрация: 07.08.2011
Сообщений: 789
Записей в блоге: 1
18.01.2012, 21:52  [ТС]     Производный класс. Перегрузка << (cout). #9
kravam, Вот так: )
Миниатюры
Производный класс. Перегрузка << (cout).  
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
18.01.2012, 22:08     Производный класс. Перегрузка << (cout). #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;
}
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
18.01.2012, 22:19     Производный класс. Перегрузка << (cout). #11
KeyGen, чё-то я не понял, у тебя mass указывает на массив элементов типа Port, нулевой из которых- элемент типа Port, так ты его и получаешь по рисунку это видно. Так, а в массиве mass элемент типа VintagePort это ПЕРВЫЙ элемент. Ты хочешь получить его данные? Ну так напиши
C++
1
cout << *(mass[1]) << endl;
И всё будет круто, или я чего-то не понимаю?
KeyGen
 Аватар для KeyGen
333 / 289 / 6
Регистрация: 07.08.2011
Сообщений: 789
Записей в блоге: 1
18.01.2012, 22:24  [ТС]     Производный класс. Перегрузка << (cout). #12
kravam, я так и писал вывод как на картинке
C++
1
2
3
4
5
6
...
    cout << "Ввывод Port:\n";
    cout << *(mass[0]);
    cout << "\n\nВывод VintagePort:\n";
    cout << *(mass[1]) << endl;
...
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
18.01.2012, 22:50     Производный класс. Перегрузка << (cout). #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];
        }
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
18.01.2012, 22:51     Производный класс. Перегрузка << (cout). #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 ссылается на винтажный порт, то позовется ф-ия печати винтажного порта (потому что она виртуальная и переопределена в винтажном порте)
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
18.01.2012, 23:09     Производный класс. Перегрузка << (cout). #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]) указывает на винтажный порт!
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
18.01.2012, 23:11     Производный класс. Перегрузка << (cout). #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;
}
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
18.01.2012, 23:15     Производный класс. Перегрузка << (cout). #17
А на пальцах? Я пойму...
А вообще если челу надо, чтобы переменная имела значение X, надо ей это значение присвоить а не простыни выкладывать.
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
18.01.2012, 23:22     Производный класс. Перегрузка << (cout). #18
два раза на пальцах объяснил и один раз на примере, что лучше чем пальцы. Если проблемы с пониманием того, как компилятор подбирает ф-ии для вызова - то тут лучше соответствующий материал поизучать (без обид). Еще раз на пример посмотрите. А лучше откомпилируйте и посмотрите, что выводится.
retmas
Жарю без масла
803 / 685 / 143
Регистрация: 13.01.2012
Сообщений: 1,580
18.01.2012, 23:23     Производный класс. Перегрузка << (cout). #19
Цитата Сообщение от kravam Посмотреть сообщение
Да для винтажного она вызывается, для винтажного. mass [1] указывает на винтажный порт
этого нет и быть не может, потому что operator>> не является виртуальной ф-ей-членом класса Port.
перегрузка ф-ии (а именно она здесь) осуществляется по статическим типам на этапе компиляции. и на этапе же компиляции генерируется код для вызова
C++
1
std::ostream & operator<<(std::ostream & os, const Port & p)
и компилятору нас*ать, каким будет на самом деле динамический тип параметра во время выполнения
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
18.01.2012, 23:25     Производный класс. Перегрузка << (cout).
Еще ссылки по теме:

C++ Перегрузка cout
C++ Разработать производный от абстрактного класса Figure класс и класс, производный от производного
C++ Написать класс строка и производный класс, ее шифрующий

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

Или воспользуйтесь поиском по форуму:
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
18.01.2012, 23:25     Производный класс. Перегрузка << (cout). #20
Как можно сделать, я знаю, просто мне кажется мой способ более простой, чем ваш. Давайте поговорим тезисно.

1) По окончанию ввода mass[0] указывает на Port, а mass [1] на элемент типа VintagePort
Согласны?
Yandex
Объявления
18.01.2012, 23:25     Производный класс. Перегрузка << (cout).
Ответ Создать тему
Опции темы

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