ООП. Пособие по ООП в С++. Создание сложных программных систем Объектно ориентированная технология
Скачать 2.1 Mb.
|
//Базовый класс – Плоская геометрическая фигура class Base { private: char nameF[20]; protected: static const double pi; public: Base(){ strcpy(nameF,"");} void set_name(char *s); char* get_name() ; double S(); //вычисление пощади double P(); //вычисление периметра }; //Модуль реализации //реаизация статической переменной класса const double pi=3.14; void Base::set_name(char *s) { strcpy(nameF,s); } char* Base::get_name() { return nameF; } double Base::S() { return 0; } double Base::P() { return 0; } //Производный - Круг class Circle:public Base { private: double r; public: Circle(){r=0;} Circle( double r1) {r=r1;} Circle(){cout<<”delete object”;} double S(); double P(); }; double Circle::S() { return pi*r*r; } double Circle::P() { return (2*3.14*r); } //Производный класс - Квадрат class Rect:public Base { private: double a,b; public: Rect(){a=b=0;} Rect(double a1, double b1){a=a1; b=b1;} double S(); double P(); }; double Rect::S() { return a*b; } double Rect::P() { return (2*a+2*b); } 7.1.1.5 Спецификаторы доступа к полям базового класса из наследника Определение базового класса и ограничения доступа к членам класса class Tbase { private: // доступны только членам этого класса int A; void fa(); protected: // доступны в классе и наследникам int B; void fb(); public: // доступны в классе, наследникам и внешним функциям int c; void fc(0; }; 7.1.1.6 Назначение ограничений доступа наследника к членам базового класса 1) Class Имя : public Имя базового класса {} – открытый базовый класс Если базовый класс подключен с использованием public, тогда: К полям, находящимся в базовом классе под защитой: private – прямого доступа к членам базового класса нет, только через методы базового класса типа get и set: public – доступ есть protected – доступ есть Пример. Наследование от открытого класса. Доступ к закрытым данным базового класса невозможен – ошибка компиляции. class Tbase { private: int a; //доступны членам – функциям класса protected: int x; // доступны в классе и наследникам public: int y; // доступны в классе, наследникам и внешним функциям }; Члены открытого базового класса в производном классе сохраняют спецификации доступа. Class TNasl:public Tbase { public: void fa() { cout<//не доступен наследникам ошибка компиляции } void fx() { cout< } void fy() { cout< } }; int main( int argc, _TCHAR* argv[]) { TNasl N1(1,2,3,4); N1.fa(); N1.fx(); N1.fy(); return 0; } Результат компиляции 2) class Имя : private Имя базового класса {} – закрытый базовый класс К полям, находящимся базом классе под защитой: private – прямого доступа к членам базового класса нет, только через методы базового класса типа get и set; public – доступа нет, только через методы базового класса типа get и set; protected – доступа нет, только через методы базового класса типа get и set. Пример. Наследование на основе закрытого базового класса class Tbase { private: int a; //доступны членам – функциям класса protected: int x; // доступны в классе и наследникам public: int y; // доступны в классе, наследникам и внешним функциям Tbase( int a1, int b1, int c1){a=a1;x=b1;y=c1;} int get_a(); int get_x(); int get_y(); }; int Tbase::get_a() { return a; }; int Tbase::get_x(){ return x; }; int Tbase::get_y(){ return y; }; }; //Доступ ко всем членам закрытого класса закрыт class TNasl: private Tbase { private: int d; public: TNasl( int a1, int b1, int c1, int d1):Tbase(a1,b1,c1) {d=d1; } void fa() { cout<//не доступен наслединкам - ошибка компиляции } void fx() { cout< } void fy() { cout< } }; int main( int argc, _TCHAR* argv[]) { TNasl N1(1,2,3,4); N1.fa(); N1.fx(); return 0; } Результат компиляции 3) class Имя : protected Имя базового класса {} – защищенный базовый класс К полям, находящимся базом классе под защитой: private – остаются private (доступа к членам базового класса нет, только через методы базового класса типа get и set) public – становятся защищенными (protected) protected – остаются защищенными class Tbase { protected: int x; // доступны в классе и наследникам public: int y;//доступны в классе, наследникам и внешним функциям private: int z; }; Class TNasl : protected Tbase { public: void f(); //имеет доступ к полям x y базового класса, но //не имеет доступа к полю z. } Примеры определения ограничения доступа к отдельным членам класса 1. Закрыть всечлены базового класса для доступа в производном классе class A { public: int x; A(){ std::cout<<"Конструктор А"; } void Display() { std::cout<<"x="< }; class B: private A{ public: B():A(){ std::cout<<"Конструктор B";} }; int main() { A O1; O1.Display(); // доступная функция B O2; O2.Display(); // не доступная функция, //так как закрытый базовый класс return 0;} 2. Открыть выборочно члены базового класса class B: private A { public : B():A(){std::cout<< "Constructor B" ;} A::Display; // элемент имени А:: означает, что член базового класса должен остаться открытым }; main() { A O1; O1.Display(); // доступная функция B O2; O2.Display();// доступная функция, так как она сделана открытой // в закрытом базовом классе } 7.1.1.7 Конструктор в производном классе Конструктор НЕ наследуется, поэтому если базовый класс имеет конструктор, то наследник должен иметь конструктор. Конструктор производного класса вызывает конструктор базового класса, чтобы инициализировать поля базового класса. Нельзя явно вызвать конструктор базового класса из конструктора наследника. Пример класса Геометрическая фигура, с двумя наследниками: Круг и Прямоугольник #include "stdafx.h" #include "string.h" #include Base { private: char nameF[20]; public: Base(); Base( char *s); void set_name( char *s); char * get_name() ; virtual double S(); //вычисление пощади virtual double P(); //вычисление периметра }; Base::Base(){ strcpy_s(nameF, "" );} Base:: Base( char *s){ strcpy_s(nameF,s);} void Base::set_name( char *s) { strcpy_s(nameF,s); } char * Base::get_name() { return nameF; } double Base::S() { return 0; } double Base::P() { return 0; } //Наследник - Круг class Circle: public Base { private: double r; public: Circle(){r=0;} Circle( double r1, char *s):Base(s){//неявный вызов конструктора r=r1; } Circle(){ cout<<"delete object"; } double S(); double P(); }; //Реализация методов double Circle::S() { return 3.14*r*r; } double Circle::P() { return (2*3.14*r); } //Производный класс - Прямоугольник class Rect: public Base { private: double a,b; public: Rect():Base(){a=b=0;} Rect( double a1, double b1, char *s):Base(s){a=a1; b=b1;} double S(); double P(); }; double Rect::S() { return a*b; } double Rect::P() { return (2*a+2*b); } int _tmain( int argc, _TCHAR* argv[]) { Base B; cout<< "P=" < << "S=" < ; Circle C(3,s); B=C; strcpy_s(s, "Circle" ); cout<< "P=" < << "S=" < "P=" < P()<< ' ' << "S=" < S()< ( int i=0;i<5;i++) Masobject[i]= new Base; strcpy_s(s, "Base" ); Masobject[0]=&Base(s); strcpy_s(s, "Circle" ); Masobject[1]=&Circle(5,s); Masobject[2]=&Circle(8,s); strcpy_s(s, "Rect" ); Masobject[3]=&Rect(2,3,s); Masobject[3]=&Rect(2,3,s); cout< 7.1.1.8 Наследование методов класса Наследуются члены базового класса с соответствующими ограничениями: методы и поля данных, они могут использоваться функциями производного класса, если они находятся под защитой public и protected и пользоваться частичными ограничениями (см.7.1.1.6). В производном классе могут быть свои члены – данные и методы. Не наследуются: • Конструктор • Дружественные функции (они не являются членами класса) • Оператор присваивания (объекту производного класса нельзя присваивать объекты базового класса). Пример доступ из производного класса к закрытым членам базового класса и вызов конструктора базового класса сlass Tbase { private: int count; public: TBase(){ count=0;} void SetCount(int c) { count=c;}; int GetCount() {return count;}; }; сlass TNasl2:public TBase { private: int secondCount; public: TNasl2(); void changecount(int n);// метод наследника } TNasl2:: TNasl2():TBase(){ //заголовок конструктора //вызов базового класса secondCount=0; } // ошибка доступа к полю void TNasl2:: changecount() { count+=1; } // нет ошибки доступа к полю void TNasl2:: changecount(int n) { SetCount(GetCount()+n); } 7.1.1.9 Использование конструктора в производном классе Пример #include #include "string.h" class TBase { private : char *basep; public : TBase( const char *s){ basep=strdup(s);} //копирование s TBase( ){ delete basep;} //освобождает ДП const char *GetStr(){ return basep;} }; //Создадим наследника и посмотрим, что происходит в производном классе class TNasl: public TBase { private : char *uppercasep; public : TNasl( const char *s); TNasl(){ delete uppercasep;} const char *GetStr(){ return uppercasep;} }; //Конструктор можно реализовать следующим образом TNasl::TNasl( const char *s):TBase(s) { uppercasep =strdup(s); //конвертируем первую букву в прописную uppercasep[0]=toupper(uppercasep[0]); } int main() { TBase O1( "hello" ); TNasl O2( "hello" ); std::cout< } 7.1.1.10 Деструктор в производном классе Деструктор требуется определить в классе, в котором определены динамически создаваемые поля данных. Деструктор должен освободить динамическую память. Деструктор разрушает любой объект при выходе объекта из области видимости. Деструктор не определен в классе, но всегда вызовется при выходе объекта из области видимости. Если конструктор производного класса должен вызывать конструктор базового класса при создании объекта производного класса, то деструктору эти строгости не нужны. Пример класса имеющего деструктор, который будет вызван при завершении программы автоматически using namespace std; class TBase { private: char *bpase; public: TBase( const char *s) {bpase=_strdup(s);} TBase(){ delete bpase;} const char *GetStr(){ return bpase;} }; class TNasl : public TBase { private: char *upperbcasep; public: TNasl( const char *s); TNasl(){ delete upperbcasep;} const char *GetUStr(){ return upperbcasep;} }; TNasl::TNasl( const char *s):TBase(s) { upperbcasep=_strupr(_strdup(s)); } int main( int argc, _TCHAR* argv[]) { //TBase O1("hello"); TNasl O2( "hello" ); cout< "PAUSE" ); return 0; } Примечание. Конструктор наследника вызовет конструктор базового класса, который создаст поле bpase и запишет в него слово hello. Затем конструктор создаст свое поле upperbcasep и запишет в него тоже слово, только прописными буквами. Пример общедоступного наследования (public) class TDate { protected: int d, m, y; public: TDate( int d1, int m1, int y1){d=d1;m=m1;y=y1;} void out() {cout< < < TNaslD: public TDate { protected: static const char mm= 'A' ; public: TNaslD( int d1, int m1, int y1):TDate(d1, m1, y1){}; void out() {cout< << char (mm)<< ' ' < int argc, _TCHAR* argv[]) { TDate O1(12, 4, 2015); O1.out(); TNaslD O2(12,4,2015); O2.out(); system( "PAUSE" ); return 0; } 7.1.1.11 Алгоритм выполнения конструктора и деструктора при создании и уничтожении производных классов Деструктор - метод, уничтожающий объект класса, после выхода объекта из области видимости. Если конструктор наследника должен вызвать конструктор базового класса, то деструктор не нуждается в таких строгостях. В производном классе явный деструктор нужен только при наличии членов, которые нужно удалять (динамические переменные), когда объект производного класса выходит из области видимости. 7.1.2 Множественное наследование Пример реализации множественного наследования Класс вещественного числа, из целой и дробной части. Целая часть числа и дробная часть – это классы, а вещественное число - производный класс. #include : int x; public : integerPartOfNumber( int x1){x=x1;} }; class floatPartOfNumber{ protected : int y; public : floatPartOfNumber( int y1){y=y1;} }; class floatNumber: public floatPartOfNumber,integerPartOfNumber{ protected : double z; public : double f( int m){ int a=m%10; if (m){ return f(m/10); } z=z*1/10+a; return z; } floatNumber( int x1, int y1):integerPartOfNumber(x1),floatPartOfNumber(y1) { z=0; int p=1; while (y>p){ p=p*10; } while (y){ z=z+y%10*1.0/p; y=y/10; p=p/10; } z=x+z; } double getNumber(){ return z;} }; int _tmain( int argc, _TCHAR* argv[]) { floatNumber O(2,345); std::cout< } 7.2 Ассоциация Создадим модель системы «Управление выдачей и возвратом книг». Основными классами является: Reader (читатель), со свойствами: numreader(номе читательского билета), FIO. +setnumreader() : void +getnumreaer() : int +setFIO() : void +getFIO() : string +Reader() -numreader : int -FIO : string Reader Book (книга) со свойствами: name, author,invnumer (инвентарный номер – уникальный номер каждой книги библиотеки) +setname() : void +setauthor() : void +setinvnum() : void +Book() +getname() : string +getauthor() : string +getinvnum() : int -name : string -author : string -invnumer : int Book Ассоциация показывает отношения между объектами-экземплярами класса. 7.2.1 Бинарная ассоциация В модель добавим класс «RecordBook» - запись о книге взятой читателем. Книга может быть включена только в одну запись, мощность связи 1 к 1. На модели Включена в запись – название ассоциации. Свойство invnumer в кассе RecordBook представляет связь с классом Book. +setname() : void +setauthor() : void +setinvnum() : void +Book() +getname() : string +getauthor() : string +getinvnum() : int -name : string -author : string -invnumer : int Book +setinvnumer() : void +setdatain() : void +setdataout() : void +getinvnumer() : int +getdatain() : string +getdataout() : string -invnumer : int -datain : string -dataout : string RecordBook -Вкючена в запись 1 1 Реализация классов class Book{ private : string name; string author; int invnumer; public : Book(string name1,string author1, int invn){ name=name1; author=author1; invnumer=invn; } void setname(string sname){ name=sname; } void setauthor(string sauthor){ author=sauthor; } void setinvnumer( int num){ invnumer=num; } string getname(){ return name; } string getauthor(){ return name; } string getinvnum(){ return name; } }; class RecordBook{ private : int invnumer; string datain; string dataout; public : void setdatain(string din){ datain=din; } void setdataout(string dout){ dataout=dout; } void setinvnumer( int num){ invnumer=num; } string getdatain(){ return datain; } string getdataout(){ return dataout; } int getinvnumer(){ return invnumer; } }; //выбрать книгу из списка int createRecordBook(vector ( int i=0;i <
<
' <
"Viberite nomer book" ; std::cin>>inv; return inv; } int main() { vector "AAA" , "Ab" ,111)); listBook.push_back(Book( "BBB" , "Bb" ,122)); listBook.push_back(Book( "CCC" , "Cb" ,133)); RecordBook R; string d1= "10.01.2019" , d2= "17.02.2019" ; R.setinvnumer(vector R.setdatain(d1); R.setdataout(d2); return 0; } 7.3 |