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

Как правильно использовать operator= при наследовании в полиморфных и неполиморфных классах - C++

Войти
Регистрация
Восстановить пароль
Другие темы раздела
C++ Как определить размер массива объявленного в другом модуле? http://www.cyberforum.ru/cpp-beginners/thread1801232.html
Возникла необходимость разбить программу на модули, и появилась проблема: Module1.cpp: ... int mas = {1, 2, 3, 4, 5}; ... Module2.cpp: ... extern int mas;
C++ Реализовать очередь с приоритетным включением на обычном массиве посмотрите код что то не правильно работает или просто не дописал норм код в методе int Adqueue() не могу сделать //1. Реализовать очередь с приоритетным включением на обычном массиве. #include <iostream> #include <time.h> using namespace std; class ExclusionProirityQueue http://www.cyberforum.ru/cpp-beginners/thread1801190.html
Вывод массива string C++
#include "stdafx.h" #include <iostream> #include <cstring> int main() { using namespace std; int sum = 0; int a;
C++ Прототип функции создающей двумерный массив
Доброго времени суток , помогите пожалуйста разобраться с заданием. Создайте функцию с ее прототипом (int a,int n). Функция во время своего выполнения должна создавать массив размерностью n на 10. #include <iostream> using namespace std; void mas(int a, int n); int main() { int n;
C++ Нужен пример кейлоггера http://www.cyberforum.ru/cpp-beginners/thread1801125.html
Срочно нужен кейлоггер который будет считывать все нажатия с клавиатуры и записывать их в текстовый файл. нужно чтоб этот кейлоггер был в процессах или в трее(главное чтоб не было видно) Кому не лень бросьте простой исходничек на с++) заранее спасибо!
C++ Почему начинающим советуют не работать с формами на С++? Часто слышала от знакомых, что лучше пока не трогать формы. С чем это связано? Как понять что уже можно с ними работать? какие знания для этого нужны ? подробнее

Показать сообщение отдельно
4elovek37
2 / 2 / 0
Регистрация: 10.10.2014
Сообщений: 28
Завершенные тесты: 1

Как правильно использовать operator= при наследовании в полиморфных и неполиморфных классах - C++

31.08.2016, 21:07. Просмотров 275. Ответов 7
Метки (Все метки)

Доброго времени суток! Изучаю книгу С. Прата "Язык программирования C++. Лекции и упражнения." Закончил 13-ю главу, посвященную наследованию и приступил к выполнению упражнений. Проблема возникла на этом упражнении:
Кликните здесь для просмотра всего текста

Союз программистов-меценатов собирает коллекцию бутылочного портвейна.
Для ее описания администратор союза разработал класс Port, Завершив определения методов для класса Port, администратор написал
производный класс Vintage Port, прежде чем был уволен

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
class Port//портвейн!
{
private:
    char * brand;
    char style[20];
    int bottles;
public:
    Port(const char * brand = "none", const char * style = "none", 
        int bottles = 0);
    Port(const Port & p);//конструктор копирования
    virtual ~Port() { delete [] brand_; }
    Port & operator=(const Port & p);
    Port & operator+=(int bottles);
    Port & operator-=(int bottles);
    int BottleCount() 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() { delete [] nickname; }
    VintagePort & operator=(const VintagePort & vp);
    void Show() const;
    friend std::ostream & operator<<(std::ostream & os, const VintagePort & p);
};
Вам поручено завершить разработку класса VintagePort.
а. Первое задание — нужно заново создать определения методов Port, т.к.
предыдущий администратор уничтожил свой код.
б. Второе задание — объясните, почему одни методы переопределены, а другие
нет.
в. Третье задание — объясните, почему функции operator= () и operator« ()
не определены как виртуальные.
г. Четвертое задание — обеспечьте определения для методов VintagePort.

В общем и целом все понятно, но увидев пункт "в" я встал в ступор. Функция operator<<() не может быть виртуальной, т.к. она friend. Но почему operator=() не виртуальная? Внимательно проглядел код последних примеров из книги - operator=() не виртуальная, но я почему-то в свое время это забыл и при выполнении упражнений с полиморфным наследованием делал ее виртуальной, и все работало. Покопавшись еще, я совсем запутался, к примеру сделав ф-ю operator= в предыдущем упражнении не виртуальной я получил рабочую программу, хотя вроде и не должно бы:
Кликните здесь для просмотра всего текста

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
/empty.h
#ifndef EMPTY_H_
#define EMPTY_H_
#include <iostream>
#include <string>
//Абстрактный базовый класс
class BaseDMA
{
private:
    char * label_;
    int rating_;
public:
    BaseDMA(const char * label = "null", int rating = 0);
    BaseDMA(const BaseDMA & rs);
    virtual ~BaseDMA();
    BaseDMA & operator=(const BaseDMA & rs);
    virtual void View() const = 0;
    friend std::ostream & operator<<(std::ostream &, const BaseDMA &);
    friend std::ostream & operator<<(std::ostream &, const BaseDMA *);
};
//Класс, просто класс
class DMA :public BaseDMA
{
 
public:
    DMA(const char * label = "null", int rating = 0);
    DMA(const DMA & rs);
    ~DMA() {}
    DMA & operator=(const DMA & rs);
    void View() const;
};
 
//Производный класс без динамического выделения памяти
//Деструктор не нужен
//Используется неявный к-р копирования
//Используется неявная операция присваивания
class LacksDMA :public BaseDMA
{
private:
    enum { COL_LEN_ = 40};
    char color_[COL_LEN_];
public:
    LacksDMA(const char * color = "blank", const char * label = "null",
        int rating = 0);
    LacksDMA(const char * color, const BaseDMA & rs);
    void View() const;
};
 
//Производный класс с динамическим выделением памяти
class HasDMA :public BaseDMA
{
private:
    char * style_;
public :
    HasDMA(const char * style = "none", const char * label = "null",
        int rating = 0);
    HasDMA(const char * style, const BaseDMA & rs);
    HasDMA(const HasDMA & hs);
    ~HasDMA();
    HasDMA & operator=(const HasDMA & rs);
    void View() const;
};
 
#endif
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
121
122
123
124
125
126
#include <iostream>
#include <cstring>
#include "empty.h"
//Методы BaseDMA
BaseDMA::BaseDMA(const char * label, int rating)
{
    label_ = new char[std::strlen(label) + 1];
    std::strcpy(label_, label);
    rating_ = rating;
}
BaseDMA::BaseDMA(const BaseDMA & rs)
{
    label_ = new char[std::strlen(rs.label_) + 1];
    std::strcpy(label_, rs.label_);
    rating_ = rs.rating_;
}
BaseDMA::~BaseDMA()
{
    delete [] label_;
}
BaseDMA & BaseDMA::operator=(const BaseDMA & rs)
{
    if(this == &rs)
        return *this;
    delete [] label_;
    label_ = new char[std::strlen(rs.label_) + 1];
    std::strcpy(label_, rs.label_);
    rating_ = rs.rating_ + 300;
    return *this;
}
void BaseDMA::View() const
{
    std::cout << "Label: " << label_ << ", Rating: " << rating_ << std::endl;
}
//Методы DMA
DMA::DMA(const char * label, int rating) :BaseDMA(label, rating)
{
    
}
DMA::DMA(const DMA & rs) :BaseDMA(rs)
{
    
}
DMA & DMA::operator=(const DMA & rs) 
{
    if (this == &rs)
        return *this;
    BaseDMA::operator=(rs);
    return *this;
}
void DMA::View() const
{
    BaseDMA::View();
}
 
//Методы LacksDMA
LacksDMA::LacksDMA(const char * color, const char * label, int rating)
    :BaseDMA(label, rating)
{
    std::strncpy(color_, color, 39);
    color_[39] = '\0';//IMHO, TAK SEBE RESHENIE
}
LacksDMA::LacksDMA(const char * color, const BaseDMA & rs)
    
{
    std::strncpy(color_, color, COL_LEN_ - 1);
    color_[COL_LEN_ - 1] = '\0';//IMHO, TAK SEBE RESHENIE
}
void LacksDMA::View() const
{
    BaseDMA::View();
    std::cout << "Color: " << color_ << std::endl;
}
 
//Методы HasDMA
HasDMA::HasDMA(const char * style, const char * label, int rating)
    :BaseDMA(label, rating)
    
{
    style_ = new char [std::strlen(style) + 1];
    std::strcpy(style_, style);
}
HasDMA::HasDMA(const char * style, const BaseDMA & rs)
    :BaseDMA(rs)
 
{
    style_ = new char[std::strlen(style) + 1];
    std::strcpy(style_, style);
}
HasDMA::HasDMA(const HasDMA & hs)
    :BaseDMA(hs)//: BaseDMA(hs)//Вызывает к-р копирования базового класса
{
    style_ = new char[std::strlen(hs.style_) + 1];
    std::strcpy(style_, hs.style_);
}
HasDMA::~HasDMA()
{
    delete [] style_;
}
HasDMA & HasDMA::operator=(const HasDMA & hs)
{
    if(this == &  hs)
        return *this;
    BaseDMA::operator=(hs);//BaseDMA::operator=(hs);//копирование базовой части
    delete [] style_;//Подготовка к операци new для style_
    style_ = new char[std::strlen(hs.style_) + 1];
    std::strcpy(style_, hs.style_);
    return *this;
}
void HasDMA::View() const
{
    BaseDMA::View();
    std::cout << "Style: " << style_ << std::endl;
}
 
//Перегрузка операции << для вызова нужного virtual метода View
std::ostream & operator<<(std::ostream & os, const BaseDMA * hs)
{
    hs->View();
    return os;
}
std::ostream & operator<<(std::ostream & os, const BaseDMA & hs)
{
    hs.View();
    return os;
}
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
#include <iostream>
#include "empty.h"
 
int main()
{
    setlocale(0,"Rus");
    using std::cin;
    using std::cout;
    using std::endl;
    BaseDMA * pdma = new DMA("DMA", 0);
    BaseDMA * phas = new HasDMA("STYLE", "HAS", 0);
    BaseDMA * placks = new LacksDMA("COLOR", "LACKS", 0);
 
    pdma->View();
    placks->View();
    phas->View();
    cout << "PDMA = PLACKS:\n";
    pdma = placks;
    pdma->View();
    placks->View();
    cout << "PLACKS = PHAS:\n";
    cout << (void *)placks << "|||||" << (void *)phas << endl;
    placks = phas;
    cout << (void *)placks << "|||||" << (void *)phas << endl;
    placks->View();
    phas->View();
    system ("pause");
    return 0;
}

Как это работает? Если мы оперируем ссылками на базовый класс, а operator=() не виртуальная (т.е. не используем таблицу виртуальных методов, и компилятор смотрит на тип указателя), то при использовании операции присваивания должна использоваться БАЗОВЫЙ_КЛАСС::operator=(), и соответственно, копироваться только базовая часть! Но в моем коде все прекрасно копируется, кроме того, получается присвоить объекту одного производного класса объект другого производного класса!
У меня ощущение, что я блуждаю в 3-х соснах. Объясните, пожалуйста, как это работает, и как правильно использовать operator=() при полиморфном наследовании и без него. Заранее благодарю.
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru