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

Перегрузка конструктора копирования и оператора присвоения - C++

Восстановить пароль Регистрация
Другие темы раздела
C++ Дальнейшее изучение С++ http://www.cyberforum.ru/cpp-beginners/thread444347.html
Вот хотел у вас спросить, что дальше можно почитать после Бьярне Страуструп Программирование: принципы и практика использования C++, и после Р.Лафоре ООП в С++, планирую купить по WinApi и что то еще хотел у вас спросить что можно еще купить почитать
C++ полноэкранный режим консоли Здравствуйте! Не могли бы подсказать, как программно переходить в полноэкранный режим в консоле? (Именно переходить, а не получать информацию, является ли режим полноэранным) Добавлено через 19 минут Функцию нашёл тут, только возникают ошибки. Код программы: #include <windows.h>; #include <wincon.h>; http://www.cyberforum.ru/cpp-beginners/thread444341.html
C++ Преобразовать выражение в постфиксную форму
Преобразовать выражение, составленное из цифр и знаков арифметических операций (+,-,*,/) в постфиксную форму. В постфиксной форме сначала записываются операнды, а затем знак операции. Обычная запись 3+4 (5-4)*2 2*(3+4)*5 Постфиксная запись 3 4 + 5 4 – 2 * 2 3 4 + * 5 *
C++ Построить некоторый Автомат на три команды
Некоторый автомат может запросить два числа и выполнить 3 команды. Команда А преобразует имеющуюся пару чисел (х, у) в (х-у,у), команда В преобразует пару чисел (х,у) в пару (х+у,у), команда С преобразует пару чисел (х,у) в пару (у,х). Составьте алгоритм и программу работы автомата.
C++ Векторы http://www.cyberforum.ru/cpp-beginners/thread444323.html
Определите полусумму длин двух векторов А(1,5; 2,5; -0,3) и В(-11,7; -9,3; 2,5; 3,7; -1,2). Вычислите, длины вектора оформив в виде функции.
C++ Модуль Разработать и отладить программу состоящую из модуля, который содержит процедуру, которая обнуляет элементы матрицы под главной диагональю и функцию, которая определяет среднеарифметическое отрицательных элементов. подробнее

Показать сообщение отдельно
stawerfar
 Аватар для stawerfar
140 / 54 / 4
Регистрация: 14.12.2010
Сообщений: 347
Записей в блоге: 1
11.02.2012, 14:08     Перегрузка конструктора копирования и оператора присвоения
Всем привет, сразу к делу. После прочтения 11 главы Лафоре столкнулся с такой бедой как понятие перегрузка оператора присвоения. Дело в том что Лафоре говорит что именно оператор присвоения является уникальным и не наследуется. Но когда создаёшь указатель на базовый класс там естественно делаешь все методы виртуальными (для полиморфизма), при раз адресации указателя происходит вызов перегруженного оператора присвоения базового класса а не производного который по факту там находиться!! Как же так? Естественно что я перегрузил эти конструкторы и в производных классах. Код ниже подскажите как мне быть?? Как вызвать нужный мне перегруженный оператор?
Базовый класс
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//класс издательство
class publication
{
    protected: 
        static const int sciMAX=100;//максимальный размер символьного массива
        metring* ch_name;//название
        float f_price;//цена
    public:
        //конструктор без параметров
        publication(void);
        //конструктор с двумя параметрами
        publication(char* ch_name, float f_price);
        //конструктор копирования
        publication(publication&);
        //диструктор
        virtual~publication(void);
        //ввод данных
        virtual void put_into_the_class(void)=0;//чисто виртуальная фукция
        //вывод данных на экран консоли
        virtual void get_out_of_the_class(void);
        //оператор присвоения
        virtual publication& operator = (publication&);
};
Конструктор копирования базового класса
C++
1
2
3
    ch_name = val.ch_name;//копирую указатель
    ch_name->icount++;//увеличиваю счётчик указывающий на количество указателей на строку
    f_price = val.f_price;//копирую другое поле класса
Перегрузка оператора присваения
C++
1
2
3
4
5
6
7
8
9
10
    if(this == &val)//если объект присваивается сам себе то выход
    {return *this;}
    if(ch_name->icount==1)
    {delete ch_name;}//если больше ни кто ни указывает на эту строку то удаляем её
    else
    {ch_name->icount++;}//иначе именьшаем счётчик указателей на строку
    ch_name= val.ch_name;//копирую указатель
    f_price = val.f_price;//копирую другое поле класса
    ch_name->icount++;//увеличиваю счётчик указывающий на количество указателей на строку
    return *this;//возвращаю ссылку на объект
Производный класс
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//класс книга
class book : public publication
{
    private:
        int i_how_meny_pic;//количество страниц
    public:
        //конструктор без параметров
        book(void);
        //конструктор копирования
        book(book&);
        //конструктор с тремя параметрами
        book(int,char*,float);
        //ввод данных
        void put_into_the_class(void);
        //вывод данных на экран консоли
        void get_out_of_the_class(void);
        //операция присвоения
        book& operator = (book&);
};
Конструктор копирования для производного (от класса издательство) класса книга
C++
1
2
3
4
5
6
7
8
//конструктор копирования
book::book(book& val)
{
    ch_name = val.ch_name;//копирую указатель
    ch_name->icount++;//увеличиваю счётчик указывающий на количество указателей на строку
    f_price = val.f_price;//копирую другое поле класса  
    i_how_meny_pic = val.i_how_meny_pic;//копирую количество страниц в книге
}
Перегрузка операции присвоения для производного (от класа издательство) класса книга
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//операция присвоения
book& book:: operator = (book& val)
{
    if(this == &val)//если объект присваивается сам себе то выход
    {return *this;}
    if(ch_name->icount==1)
    {delete ch_name;}//если больше ни кто ни указывает на эту строку то удаляем её
    else
    {ch_name->icount++;}//иначе именьшаем счётчик указателей на строку
    ch_name= val.ch_name;//копирую указатель
    f_price = val.f_price;//копирую другое поле класса
    i_how_meny_pic = val.i_how_meny_pic;//копирую количество страниц в книге
    ch_name->icount++;//увеличиваю счётчик указывающий на количество указателей на строку
    return *this;//возвращаю ссылку на объект
}
Производный класс "тип" от класса издательство
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//класс тип
class type : public publication
{
    private:
        float f_time;//время записи книги в менутах
    public:
        //конструктор без параметров
        type(void);
        //конструктор копирования
        type(type&);
        //конструктор с тремя параметрами
        type(float,char*,float);
        //ввод данных
        void put_into_the_class(void);
        //вывод данных на экран консоли
        void get_out_of_the_class(void);
        //оператор присваения
        type& operator = (type&);
 
};
Конструктор копирования производного(от класса издательство) класса "тип"
C++
1
2
3
4
5
6
7
8
//конструктор копирования
type::type(type& val)
{
    ch_name = val.ch_name;//копирую указатель
    ch_name->icount++;//увеличиваю счётчик указывающий на количество указателей на строку
    f_price = val.f_price;//копирую другое поле класса  
    f_time = val.f_time;//коприрую время записи книги в минутах
}
Перегрузка оператора присваения производного (от класса издательство) класса "тип"
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//оператор присваения
type& type:: operator = (type& val)
{
    if(this == &val)//если объект присваивается сам себе то выход
    {return *this;}
    if(ch_name->icount==1)
    {delete ch_name;}//если больше ни кто ни указывает на эту строку то удаляем её
    else
    {ch_name->icount++;}//иначе именьшаем счётчик указателей на строку
    ch_name= val.ch_name;//копирую указатель
    f_price = val.f_price;//копирую другое поле класса
    f_time = val.f_time;//коприрую время записи книги в минутах
    ch_name->icount++;//увеличиваю счётчик указывающий на количество указателей на строку
    return *this;//возвращаю ссылку на объект
}
Использование инструметрария:
Идей заключается в следующем создается в динамической памяти массив указателей на базовый класс.
И процессе работы программы на уровне пользователя решается какой класс будет создан вот кусок кода
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
            std::cout<<"Выбирите тип книги audy или paper (a,p) :";
            std::cin>>str_val;
            if(str_val=="paper"||str_val == "p")
            {
                *(publist+n)=new book;//выделение памяти под необходимый производный класс
                (*(publist+n))->put_into_the_class();//взятие данный от пользователя
                n++;//увеличение счётчика элиментов массива
                break;//выход из внутреннего цикла
            }
            else if(str_val =="audy"||str_val == "a")//если ползователь ввел аудио книгу
            {
                *(publist+n)=new type;//выделение памяти под необходимый производный класс
                (*(publist+n))->put_into_the_class();//взятие данный от пользователя
                n++;//увеличение счётчика элиментов массива
                break;//выход из внутреннего цикла
            }
Далее предусмотрено динамическое выделение памяти при необходимости т.е. если пользователь не угомонился и продолжает вводить данные в массив вот код:
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
if(n>=ilenpublist)//елси не хватает места для элементов в массиве то перевыделяем память
         {
            publication** temp = new publication*[ilenpublist];//временный массив для переброски данных
            for(int i =0 ; i<ilenpublist;i++)
            {   //проверяю тип указателя и выделяю в новый временный массив соответствующую память
                if(dynamic_cast<book*>(*(publist+i)))
                {
                    *(temp+i) = new book;//выделяю память
                    *(*(temp+i))=*(*(publist+i));//побитовое копирование между объектами
                }
                //проверяю тип указателя и выделяю в новый временный массив соответствующую память
                else if(dynamic_cast<type*>(*(publist+i)))
                {
                    
                    *(temp+i) = new type;//выделяю память
                    *(*(temp+i))=*(*(publist+i));//побитовое копирование между объектами
                }
            }
            //освобождаю память для перевыдиления
            for(int i =0 ; i<ilenpublist;i++)
            {delete publist[i];}
            //выделяю новый массив на один элемент больше чем предыдуший
            publist = new publication*[n+1];//указатель на базовый класс
            //возвращаю на место уже введеный данные пользователем
            for(int i=0;i<ilenpublist;i++)
            {   //проверяю тип указателя и выделяю в новый временный массив соответствующую память
                if(dynamic_cast<book*>(*(temp+i)))
                {
                    *(publist+i) = new book;//выделяю память
                    *(*(publist+i))=*(*(temp+i));//копирование между объектами
                }
                //проверяю тип указателя и выделяю в новый временный массив соответствующую память
                else if(dynamic_cast<type*>(*(temp+i)))
                {
                    
                    *(publist+i) = new type;//выделяю память
                    *(*(publist+i))=*(*(temp+i));//копирование между объектами
                }
                
            }
            ilenpublist = n;//контроль реального количества элементов в массиве
            //освобождаю память из под временной переменной
            for(int i =0 ; i<ilenpublist-n;i++)
            {delete temp[i];}
         }
Вот в этой строке 31 и 38 почему то вызывается оператор присвоения базового класса а не соответствующего производного
C++
1
*(*(publist+i))=*(*(temp+i));//копирование между объектами
Как мне разрешить эту ситуацию?

Добавлено через 1 час 11 минут
Если кому интересно, то я решил эту проблему вот так:
для класса "тип"
C++
1
2
3
//преобразую указатель на базовый класс на указатель на соответствующий производныый
//поэлиментное копирование между объектами
*(dynamic_cast<type*>(*(publist+i)))=*(dynamic_cast<type*>(*(temp+i)));
для класса книга
C++
1
2
3
//преобразую указатель на базовый класс на указатель на соответствующий производныый
//поэлиментное копирование между объектами
*(dynamic_cast<book*>(*(publist+i)))=*(dynamic_cast<book*>(*(temp+i)));
Теперь всё работает как надо т.е. вызывается перегруженный оператор присваения именно того класса на который указывает указатель в данный момент.
НО возник вопрос-почему так? Неужели если работаешь с указателями при полиморфизме необходимо постоянно вручную преобразовывать указатели? И почему казалось бы альтернативный способ не приносит тех же результатов
C++
1
2
*(publist+i) = dynamic_cast<book*>(*(publist+i))
*(*(publist+i)) = *(*(temp+i));
Это всё очень странно и не понятно, да и самое удивительно то что перед операцией присвоения я проверял с помощью функции typeid какому классу принадлежит созданный объект. Так вот всё нормально
функция показывала что в памяти содержиться тот или иной но нужный в конкретной ситуации объект, но всеравно продолжал вызываться перегруженный метод присвоения базового класса.
Может кто нибудь объяснить? Ни у Лафоре ни у Павловской я этого не нашёл
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
 
Текущее время: 00:12. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru