Главная страница
Навигация по странице:

  • Виртуальные функции и полиморфизм.

  • Задания для самостоятельного решения

  • BoolVector ) от класса Vector

  • Лабораторная работа № 6

  • Практ. по классам_посмотреть. Учебнометодическое пособие для студентов механикоматематического факультета минск бгу 2005 2 удк 681. 142. 2(072)


    Скачать 0.5 Mb.
    НазваниеУчебнометодическое пособие для студентов механикоматематического факультета минск бгу 2005 2 удк 681. 142. 2(072)
    Дата03.10.2022
    Размер0.5 Mb.
    Формат файлаpdf
    Имя файлаПракт. по классам_посмотреть.pdf
    ТипУчебно-методическое пособие
    #710353
    страница3 из 4
    1   2   3   4

    Тема. Наследование
    Теоретическое введение.
    Важнейшим принципом ООП, реализованным в С++, является наследование. Класс, который наследуется, называется базовым классом, а наследующий класс –

    34
    производным классом. Указателю на объект базового класса можно присвоить значение указателя на объект производного класса.
    Все члены класса из разделов
    public
    и
    protected
    наследуются, а члены из раздела
    private –
    нет
    .
    Члены раздела
    protected
    являются частными для базового и производного классов. При наследовании базового класса к его членам также может объявляться спецификатор
    доступ
    class имя_класса: доступ имя_базового_класса
    {/*члены класса*/}
    Cпецификатор
    доступ
    базового класса при наследовании может принимать одно из трех значений:
    public
    (по умолчанию),
    private,
    protected.
    Если спецификатор принимает значение
    public,
    то все члены разделов
    public
    и
    protected
    базового класса становятся членами разделов
    public
    и
    protected
    производного класса. Если доступ имеет значение
    private
    , то все члены разделов
    public
    и
    protected
    становятся членами раздела
    private
    производного класса. Если доступ имеет значение
    protected
    , то все члены разделов
    public, protected
    становятся членами раздела
    protected
    производного класса.
    Конструкторы и деструкторы базовых классов не наследуются
    ,
    однако при создании объектов производных классов конструкторы базовых классов выполняются в порядке наследования, а деструкторы в обратном порядке. При необходимости передачи аргументов конструктору базового класса из производного класса используется следующий синтаксис: к
    онструктор_производного_класса(арг):base(арг)
    {/*тело конструктора производного класса*/}
    Множественное наследование.
    Один класс может наследовать атрибуты двух и более базовых классов, которые перечисляются после двоеточия через запятую. Если базовые классы содержат конструкторы, то они вызываются поочередно в порядке перечисления.
    Виртуальные функции и полиморфизм.
    Механизм виртуальных функций в ООП используется для реализации полиморфизма: созда- ния метода, предназначенного для работы с различными объектами за счет механизма позднего связывания (late binding). Виртуальные функции объявляются в базовом и производных классах с ключевым словом
    virtual
    . При этом каждый объект класса, управляемого из ба- зового класса с виртуальными функциями, имеет указатель на vmtbl
    (virtual method table), содержащую адреса виртуальных функций. Эти

    35
    адреса устанавливаются в адреса нужных для данного объекта функ- ций во время выполнения.
    В отличие от перегружаемых функций виртуальные объявляются в порожденных классах с тем же именем, возвращаемым значением и типом аргументов. Если различны типы аргументов, виртуальный ме- ханизм игнорируется. Тип возвращаемого значения переопределить нельзя.
    Основная идея в использовании виртуальной функции состоит в следующем: она может быть объявлена в базовом классе, а затем пе- реопределена в каждом производном классе. При этом доступ через указатель на объект базового класса осуществляется к этой функции из базового класса, а доступ через указатель на объект производного класса – из производного класса. То же происходит при передаче функции объекта производного класса, если аргумент объявлен как базовый класс.
    Абстрактные классы – это классы, содержащие чисто абстракт-
    ные виртуальные функции. Чисто абстрактные виртуальные функции при объявлении в классе приравниваются к нулю. Абстрактные клас- сы используются только для наследования, так как объекты таких классов не могут быть созданы.
    Пример.
    Создаются три класса: MyPoint (базовый класс – «Точ- ка»), MyEllipse (производный класс от класса MyPoint – «Окруж- ность») и MyCylinder (производный класс от класса MyEllipse – «Ци- линдр»). Классы объявлены в файле MyClass.h. Используются кнопки:
    Button1 – очистка области для рисования (компонент Image1), Button2
    – создание объекта класса MyPoint и рисование точки, Button3 – соз- дание объекта класса MyEllipce и рисование окружности, Button4 – создание объекта класса MyCylinder и рисование цилиндра, компо- ненты СSpinEdit1 – СSpinEdit4 для задания координат точки и разме- ров фигур, а также перемещения объектов в области рисования.
    Заголовочный файл
    Myclass.h
    //***************** class MyPoint ************************** class MyPoint { int x,y; public: int GetX(){return x;} int GetY(){return y;} void SetX(int x1){x=x1;} void SetY(int y1){y=y1;}
    MyPoint(int xx=0,int yy=0){x=xx;y=yy;} virtual void Show(); virtual bool Checking();

    36
    // Проверка, не выходит ли точка за пределы области рисования ? virtual void MoveTo(int x1,int y1);
    };
    //**************classs MyEllipse ************************** class MyEllipse:public MyPoint { int xa,yb; public: int GetXA(){return xa;} int GetYB(){return yb;} void SetXA(int xa1){xa=xa1;} void SetYB(int yb1){yb=yb1;}
    MyEllipse(int a=0,int b=0,int c=0,int d=0):MyPoint(a,b)
    {xa=c;yb=d;} virtual void Show(); virtual bool Checking();
    // Проверка, не выходит ли окружность за пределы области рисования ?
    };
    //**************** class MyCylinder ************************ class MyCylinder:public MyEllipse { int h; public: int GetH(){return h;} void SetH(int h1){h=h1;}
    MyCylinder(int X=0,int Y=0,int R=0,int H=0):MyEllipse(X,Y,R,R/2)
    {h=H;} void Show(); bool Checking();
    // Проверка, не выходит ли цилиндр за пределы области рисования ?
    };
    //****************** class MyCylinder ******************** bool ExistFigure=false;//Если ExistFigure==false, объект не изображался
    MyPoint *Figure;//- Указатель на базовый класс MyPoint.
    Файл
    Unit1.Cpp
    #include
    #pragma hdrstop
    #include "Unit1.h"
    #include "Myclass.h"
    #pragma package(smart_init)
    #pragma link "CSPIN"
    #pragma resource "*.dfm"
    TForm1 *Form1;
    __fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)
    { }
    //********** Реализация класса MyPoint ************************ void MyPoint::Show()
    ( Form1->Image1->Canvas->Pixels[x][y]=clRed;} bool MyPoint::Checking(){

    37
    //- Проверка, не выходит ли точка за пределы области рисования ? if((x>=0)&&(x<=Form1->Image1->Width)&&(y>=0)&&
    (y<=Form1->Image1->Height)) return true; else return false;
    } void MyPoint::MoveTo(int x1,int y1)
    { // если выходим за область рисования, то точку не сдвигаем. int a=x,b=y; x=x1;y=y1; if(!Checking()){x=a;y=b;}
    }
    //***********Реализация класса MyEllipse ********************** void MyEllipse::Show()
    {
    Form1->Image1->Canvas->Ellipse(GetX()-xa,GetY()-yb,GetX()+xa,GetY()+yb);
    }
    // Проверка, не выходит ли окружность за пределы области рисования ? bool MyEllipse::Checking()
    { int rabx=GetX(),raby=GetY();
    SetX(GetX()-xa);SetY(GetY()-yb); if(MyPoint::Checking())
    {
    SetX(GetX()+2*xa);SetY(GetY()+2*yb); if(MyPoint::Checking())
    {
    SetX(rabx);SetY(raby); // восcтанавливаем координаты x,y. return true;
    }
    }
    SetX(rabx);SetY(raby); // восcтанавливаем координаты x,y. return false;
    }
    //**********Реализация класса MyCylinder ************************ void MyCylinder::Show()
    {
    MyEllipse::Show();
    Form1->Image1->Canvas->MoveTo(GetX()-GetXA(),GetY());
    Form1->Image1->Canvas->LineTo(GetX()-GetXA(),GetY()-h);
    Form1->Image1->Canvas->MoveTo(GetX()+GetXA(),GetY());
    Form1->Image1->Canvas->LineTo(GetX()+GetXA(),GetY()-h);
    SetY(GetY()-h);
    MyEllipse::Show();
    SetY(GetY()+h);
    } bool MyCylinder::Checking()
    {

    38
    if(MyEllipse::Checking())
    {
    SetY(GetY()-h); if(MyEllipse::Checking()){SetY(GetY()+h);return true;}
    } return false;
    } void __fastcall TForm1::Button1Click(TObject *Sender)
    { // Чистим "графическое" окно
    Image1->Canvas->FillRect(Rect(0,0,Image1->Width,Image1->Height));
    ExistFigure=false;
    } void __fastcall TForm1::Button2Click(TObject *Sender)
    { if(ExistFigure==true)delete Figure;
    Image1->Canvas->FillRect(Rect(0,0,Image1->Width,Image1->Height));
    // Рисуем точку, проверив её попадание в область рисования
    Figure=new MyPoint(CSpinEdit1->Value,CSpinEdit2->Value);
    ExistFigure=true; if(Figure->Checking()) Figure->Show(); else ShowMessage("Точка не попадает в область рисования!");
    } void __fastcall TForm1::Button3Click(TObject *Sender)
    { if(ExistFigure==true) delete Figure;
    Image1->Canvas->FillRect(Rect(0,0,Image1->Width,Image1->Height));
    // Рисуем окружность, проверив её попадание в область рисования
    Figure=new MyEllipse(CSpinEdit1->Value,CSpinEdit2->Value,
    CSpinEdit3->Value,CSpinEdit3->Value);
    ExistFigure=true; if(Figure->Checking())Figure->Show(); else ShowMessage("Окружность не помещается в область рисования!");
    } void __fastcall TForm1::Button4Click(TObject *Sender)
    { if(ExistFigure==true) delete Figure;
    Image1->Canvas->FillRect(Rect(0,0,Image1->Width,Image1->Height));
    // Рисуем цилиндр, проверив его попадание в область рисования
    Figure=new MyCylinder(CSpinEdit1->Value,CSpinEdit2->Value,
    CSpinEdit3->Value,CSpinEdit4->Value);
    ExistFigure=true; if(Figure->Checking())Figure->Show(); else ShowMessage("Цилиндр не помещается в область рисования!");
    } void __fastcall TForm1::CSpinEdit1Change(TObject *Sender)
    { if(ExistFigure==true){

    39
    Image1->Canvas->FillRect(Rect(0,0,Image1->Width,Image1->Height));
    Figure->MoveTo(CSpinEdit1->Value,CSpinEdit2->Value);
    Figure->Show();
    }
    } void __fastcall TForm1::CSpinEdit2Change(TObject *Sender)
    { if(ExistFigure==true){
    Image1->Canvas->FillRect(Rect(0,0,Image1->Width,Image1->Height));
    Figure->MoveTo(CSpinEdit1->Value,CSpinEdit2->Value);
    Figure->Show();
    }
    }
    Задания для самостоятельного решения
    При выполнении данной работы необходимо определить базовый класс и производные от него классы. Предусмотреть передачу аргу- ментов конструкторам базового класса; использование виртуальных и перегруженных функций; обработку исключительных ситуаций.
    Вариант А
    В следующих заданиях требуется создать базовый класс (как вари- ант абстрактный базовый класс) и определить общие методы show ( ), get ( ), set ( ) и другие, специфические для данного класса. Создать производные классы, в которые добавить свойства и методы.
    Часть методов переопределить. Создать массив объектов базового класса и заполнить объектами производных классов. Объекты произ- водных классов идентифицировать конструктором по имени или идентификационному номеру.
    Вызвать метод show ( ) базового класса и просмотреть массив объ- ектов.
    Использовать объекты для моделирования реальных ситуаций.
    1. Создать базовый класс «Транспортное средство» и производные классы «Автомобиль», «Велосипед», «Повозка». Подсчитать время и стоимость перевозки пассажиров и грузов каждым транспортным средством.
    2. Создать базовый класс «Грузоперевозчик» и производные клас- сы «Самолет», «Поезд», «Автомобиль». Определить время и стои- мость перевозки для указанных городов и расстояний.
    3. Создать аналогичный базовый класс «Пассажироперевозчик» и производные классы «Самолет», «Поезд», «Автомобиль». Определить время и стоимость передвижения.

    40 4. Изменить задания 1–3, чтобы базовый класс стал абстрактным.
    Сделать некоторые методы абстрактными.
    5. Создать базовый класс «Учащийся» и производные классы
    «Школьник» и «Студент». Создать массив объектов базового класса и заполнить этот массив объектами. Показать отдельно студентов и школьников.
    6. Создать базовый класс «Музыкальный инструмент» и произ- водные классы «Ударный», «Струнный», «Духовой». Создать массив объектов «Оркестр». Выдать состав оркестра, переопределив метод.
    7. Определить базовый класс «Множество» и производный класс
    «Кольцо» (операции сложения и умножения обе коммутативные и ас- социативные, связанные законом дистрибутивности; сложение обла- дает обратной операцией – вычитанием). Ввести кольца целых чисел, многочленов, систему классов целых чисел, сравнимых по модулю.
    Кольцо является полем, если в нем определена операция деления, кроме деления на нуль. Рациональные числа, дробно рациональные функции.
    8. Создать абстрактный класс «Работник фирмы» и производные классы «Менеджер», «Администратор», «Программист».
    9. Создать базовый класс «Домашнее животное» и производные классы «Собака», «Кошка», «Попугай» и др. С помощью конструкто- ра установить имя каждого животного и его характеристики.
    10. Создать базовый класс «Садовое дерево» и производные клас- сы «Яблоня», «Вишня», «Груша» и др. С помощью конструктора ав- томатически установить номер каждого дерева. Принять решение о пересадке каждого дерева в зависимости от возраста и плодоношения.
    Вариант Б
    1. Создать класс Item (единица хранения в библиотеке), содержа- щий данные-члены: invNumber – инвентарный номер и taken – взято на руки или имеется в наличии, а также методы: virtual void Show(); //показать информацию о единице хранения bool isAvailable(); // есть ли единица хранения в наличии ? int GetinvNumber(); //возвращает инвентарный номер void Take(); // операция «взять» void Return(); // операция «вернуть»
    Построить производные классы Book и Magazin. Класс Book со- держит данные-члены: author, title, publisher, year и методы: Author();
    Title(); Publisher(); YearOf Publishing(); Show().
    Класс Magazin включает данные-члены: volume; number; year; title и методы: Volume(); Title(); Number(); Year(); Show().

    41 2. Создать базовый класс Polygon (многоугольник). Класс должен содержать методы для рисования многоугольника, вычисления пери- метра, нахождения площади и др. Построить производный класс Tri- angle (треугольник), содержащий также методы для нахождения точки пересечения медиан, длин медиан, длин биссектрис, координат точек пересечения биссектрис, высот треугольника.
    3. Создать абстрактный класс Shape для рисования плоских фигур.
    Построить производные классы Square (квадрат, который характери- зуется координатами левого верхнего угла и длиной стороны), Circle
    (окружность с заданными координатами центра и радиусом), Ellipse
    (эллипс с заданными координатами вершин описанного вокруг него прямоугольника), позволяющие рисовать указанные фигуры, а также передвигать их на плоскости.
    4. Создать класс CPoint – точка и производные от него классы
    CcoloredPoint и CLine. На основе классов CcoloredPoint и CLine со- здать класс CcoloredLine. Все классы должны иметь методы для уста- новки и получения значений всех координат, а также изменения цвета и получения текущего цвета.
    5. Описать базовый класс Stroka. Обязательные данные-члены класса: указатель типа char – для хранения строки; значение типа int – длина строки.
    Методы: конструктор без параметров; конструктор, принимающий в качестве параметра C-строку (заканчивается нулевым байтом); кон- структор копирования; получение длины строки; очистка строки (сде- лать строку пустой); деструктор.
    Описать производный класс «БИТОВАЯ_СТРОКА» (строки дан- ного класса могут содержать только символы ‘0’ и ‘1’). Если в основе инициализирующей строки встретятся любые символы, отличные от допустимых, то БИТОВАЯ_СТРОКА становится пустой. Содержимое строки рассматривается как двоичное представление целого числа со знаковым разрядом. Отрицательные числа хранятся в дополнительном коде.
    Обязательные методы: конструктор без параметров; конструктор, принимающий в качестве параметра C-строку; конструктор копирова- ния; деструктор; изменение знака числа (перевод числа в дополни- тельный код).
    Переопределить следующие операции (длина строки результата в случае необходимости расширяется влево знаковым разрядом): при- сваивание; сложение (+); проверка на равенство (==).

    42 6. Создать производный класс «СТРОКА10» (целое неотрицатель- ное десятичное число) от класса «СТРОКА» (описание приведено выше).
    Методы: конструктор без параметров; конструктор, принимающий в качестве параметра C-строку; конструктор копирования; деструктор; метод, определяющий, можно ли представить данное число в формате int; метод, определяющий, равно ли число нулю; метод, возвращаю- щий представление числа в виде целого (int); метод, удаляющий не- значащие нули.
    Переопределить операции: сложение (+); проверка на больше (по значению) (>); проверка на меньше (<); присваивание (=).
    7. Создать производный класс «БУЛЕВ ВЕКТОР» (
    BoolVector
    ) от класса
    Vector
    . Компоненты принимают значения из множества {0,1}.
    Методы: конструктор без параметров; конструктор, принимающий в качестве параметров указатель на массив целого типа (если эле- менты массива содержат числа, отличные от 0 и 1, то создается пустой вектор) и размер вектора; конструктор копирования; деструктор; ме- тод, возвращающий число единиц в векторе; метод, возвращающий позицию самой левой единицы в векторе.
    Переопределить операции: поразрядная конъюнкция (&); пораз- рядная дизъюнкция (|); поразрядная инверсия (

    ); поразрядная опера- ция ИСКЛЮЧАЮЩЕЕ ИЛИ (^); присваивание (=).
    8. Создать производный класс «ТРОИЧНЫЙ ВЕКТОР» от класса
    Vector
    . Компоненты принимают значения из множества {0,1,2}.
    Методы: конструктор без параметров; конструктор, принимающий в качестве параметров указатель на массив целого типа и размер век- тора; конструктор копирования; деструктор; проверка двух векторов на ортогональность (два троичных вектора называются ортогональ- ными, если в них существует пара одноименных компонент, имеющих в одном из векторов значение 0, а в другом – 1); метод, возвращаю- щий число компонент в векторе, принимающих значение 2.
    Переопределить операции: присваивание (=); поразрядная конъ- юнкция (пересечение) двух не ортогональных векторов (&): 0&0=0,
    1&1=1, 2&2=2, 0&2=0, 2&0=0, 1&2=1, 2&1=1; индексирование ([]).
    9. Создать производный класс «БУЛЕВА МАТРИЦА» от класса
    «ЦЕЛОЧИСЛЕННАЯ МАТРИЦА».
    Методы: конструктор без параметров; конструктор, принимающий в качестве параметров целочисленный двумерный массив, содержа- щий матрицу, и ее размеры n и m; конструктор копирования; деструк- тор; метод возвращает число единиц в матрице; метод, возвращающий

    43
    α
    -каноническую матрицу (в исходной матрице удалены повторяю- щиеся строки; строки составлены в порядке возрастания неотрица- тельных чисел, в качестве двоичных кодов которых рассматриваются данные строки).
    Переопределить операции: поэлементная конъюнкция двух матриц
    (&); поэлементная дизъюнкция двух матриц (|); поэлементная опера- ция ИСКЛЮЧАЮЩЕЕ ИЛИ двух матриц (^); произведение двух мат- риц A=[a ij
    ] и B=[ b jk
    ], где i=
    1,n
    , j=
    1,m
    , k=
    1,l
    (*). При вычислениях опе- рация целочисленного умножения заменяется конъюнкцией, а сложе- ние – дизъюнкцией; присваивание (=).
    10. Создать производный класс «МИНОР» для базового класса
    «МАТРИЦА» размерности n
    ×
    m. Переопределить для производного класса операции и методы (см. лаб. работу № 2, задание № 4).
    11. Расширить возможности стандартного класса Time, чтобы можно было выводить время дня: утро, вечер и т. д.
    12. Расширить возможности стандартного класса Date, чтобы можно было выводить время года: зима, лето и т. д.
    13. Расширить возможности класса Annotation, чтобы можно было выводить время и дату изменения аннотации.
    14. Расширить возможности класса Dictionary, чтобы можно было выводить дату последнего изменения в словаре.
    15. Расширить возможности класса File, чтобы можно было выво- дить время и дату создания файла.
    16. Расширить возможности класса Stack, чтобы можно было вы- водить время последнего сеанса работы со стеком.
    17. Определить базовый класс для работы с прямоугольными мат- рицами, предусмотрев ввод-вывод матриц и выполнение следующих операций: сложение матриц; умножение матрицы на скаляр; переста- новка строк матрицы по заданному вектору транспозиции; переста- новка столбцов матрицы по заданному вектору транспозиции. В про- изводном классе реализовать указанные операции для квадратных матриц, добавив выполнение следующих операций:
    транспонирование матрицы; умножение матриц.
    Тесты
    1. Какая из записей является правильной записью абстрактного класса?
    Варианты ответа:
    1) abstract class A{virtual f()=0;};
    *2) class A{virtual f()=0;};
    3) class A{virtual f();};

    44 2. Абстрактный класс – это класс, в котором:
    1) есть хотя бы один виртуальный метод;
    2) есть виртуальный конструктор;
    3) есть виртуальный деструктор;
    *4) есть чисто виртуальный метод.
    3. Основная проблема множественного наследования состоит в:
    1) замедлении выполнения программ;
    2) необходимости явно указывать, к какому базовому классу принадлежит метод;
    *3) возможности существования двух экземпляров объекта базового класса;
    4) неэкономном расходовании памяти.
    4. Если записано class A{public:virtual void f(){cout<<1;}}; class B:public A {public:virtual void f(){cout<<2;}}; то что будет напечатано, если
    B b;A &a=b; a.f(); ?
    Варианты ответа:
    *1) 2; 2) 21; 3) 12; 4) 1; 5) ошибка.
    5. Если записано class A {public:void f(){cout<<1;}}; class B:public A{public: void f(){cout<<2;}}; то что будет напечатано, если
    B b; b.f(); ?
    Варианты ответа:
    *1) 2; 2) 21; 3) 12; 4) 1.
    6. Если записано class A{public:virtual void f(){cout<<1;}}; class B:public A{public:virtual void f(){cout<<2;}}; то что будет напечатано, если
    B b; b.f(); ?
    Варианты ответа:
    *1) 2; 2) 21; 3) 12; 4)1; 5)ошибка.
    Лабораторная работа № 6
    1   2   3   4


    написать администратору сайта