Справочник от Автор24
Поделись лекцией за скидку на Автор24

Наследование. Производные классы в C++, Java

  • 👀 489 просмотров
  • 📌 419 загрузок
Выбери формат для чтения
Статья: Наследование. Производные классы в C++, Java
Найди решение своей задачи среди 1 000 000 ответов
Загружаем конспект в формате pdf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Конспект лекции по дисциплине «Наследование. Производные классы в C++, Java» pdf
Наследование. Производные классы в C++, Java. 1) Производный класс, наследование полей и методов и добавление новых полей и методов на С++ Имеем класс Record (min,sec), введем новый класс Sprint, бег на короткие дистанции, учитывающий десятые доли секунды спортсмена (int dec) . В классе добавим метод Putdec , устанавливающий количество десятых долей и Numberdec, вычисляющий общее число десятых долей секунды у объектов (например, для сравнения результатов). class Record { public: void Init (int m,int s); int Numbersec(); private: int min; int sec; }; int Record::Numbersec() { return min*60+sec; } void Record::Init(int m,int s) { min=m; sec=s; } // наследуемый класс class Sprint : public Record // Sprint-наследник Record { public: // новые методы Sprint void Putdec(int d); int Numberdec(); private: // новое поле Sprint int dec; }; В класссе Sprint имеются также в результате наследования public методы Numbersec, Init и private поля min, sec. 1 void Sprint::Putdec(int d) { dec=d; } int Sprint::Numberdec() { int k; k=Numbersec(); return k*10+dec; } int main(int argc, char* argv[]) { int m,n; Record x,y; x.Init(4,36); // min=4 sec=36 y.Init(2,4); // min=2 sec=4 Sprint z; z.Init(1,8); // min=1 sec=8 наследование z.Putdec(4); // dec=4 m=z.Numberdec(); // m=684 n=z.Nubersec(); // n=68 вызов наследуемого метода } 2) Модификатор доступа protected Заменим вызов Numbersec() из Numberdec прямым вычислением: int Sprint::Numberdec() { int k; k=min*60+sec; // вместо k=Numbersec(); return k*10+dec; } Ошибка! min, sec is not accessible min , sec определены как private в Record и не могут вызываться из методов другого класса Sprint, даже после наследования. Исправление: class Record { public: void Init (int m,int s); int Numbersec(); 2 protected: int min; int sec; }; // вместо private: К полям и методам из protected могут обращаться как методы Record, так и методы всех наследуемых классов, (Sprint). class A { ...... protected: int x; .... }; ...... class B : public A { .... } class C : public B { .... }; Идентификатор x может появиться в любом методе классов A, B, C. Объект базового класса, объявленный в производном не имеет доступа к private и protected полям в C++. class Record { public: void Init (int m,int s); int Numbersec(); protected: int min; private: int sec; }; int Record::Numbersec() { return min*60+sec; } void Record::Init(int m,int s) { 3 min=m; sec=s; } class Sprint : public Record // Sprint-наследник Record { public: // новые методы Sprint void Putdec(int d); int Numberdec(); private: // новое поле Sprint int dec; }; int Sprint::Numberdec() { int k; k=Numbersec(); return k*10+dec; } void Sprint::Putdec(int d) { dec=d; Record c; c.min=5; // нет доступа к protected c.sec=10; // нет доступа к prvate } В Java такой доступ есть Java class Record { protected int min,sec; public Record(int m,int s) { min=m; sec=s; } } class Sprint extends Record { int dec; 4 public void Putdec(int d) { Record v=new Record(3,6); v.min=8; // доступ к protected объекта базового класса из производного класса dec=d; } public Sprint(int m,int s,int d) { super(m,s); // вызов конструктора базового класса dec=d; } } Инкапсуляция: public, private, protected разграничивают доступ к полям и методам. 3) Модификатор в заголовке наследуемого класса class Sprint : public Record // public - открытое наследование public означает, что наследуемые поля из Record остаются без изменения: Record public -> Sprint public Record protected -> Sprint protected Record private -> Sprint private Другие варианты: class Sprint : protected Record // защищенное наследование Наследуемые поля и методы перестают быть public Record public -> Sprint protected Record protected -> Sprint protected Record private -> Sprint private class Sprint : private Record // закрытое наследование Все наследуемые поля и методы становятся private Record public -> Sprint private Record protected -> Sprint private Record private -> Sprint private Пример закрытого наследования. class Record { public: void Init (int m,int s); int Numbersec(); protected: int min; 5 int }; sec; class Sprint : private Record { ..... int main(int argc, char* argv[]) { int m,n; Record x; x.Init(1,8); // правильно Sprint z; z.Init(1,8); // min=1 sec=8 ошибка, Init теперь private z.Putdec(4); // dec=4 правильно Putdec определена в Sprint как public } В Java используется только открытое наследование 4) Множественное наследование В C++ класс может быть наследником нескольких классов. class Record { public: .......... protected: int min,sec; ........... } class Person { public: .......... protected: char Fam[30]; int Vozrast; ............. } class Sportsman : public Person , public Record { public: .......... private: 6 int Category; // разряд спортсмена ............ } В классе Sportsman наследуются поля min, sec, Fam,Vozrast. Пусть в классе Record имеется поле weight – вес, который поднял штангист и такое же поле в классе Person – собственный вес человека. class Record { public: int weight; ....... } class Person { public: char Fam[30]; int Vozrast; int weight; ...... } class Sportsman : public Person , public Record { public: void Putweight(int x); private: int Category; // разряд спортсмена ............ } void Sport5sman::Putweight(int x) { weight=m; // какое weight из двух ? ...... } Решение – указывать явно класс. Person::weight=x; Недостаток в данном операторе содержится информация что Sportsman производный от Person. В Java частично множественное наследование реализуется в интерфейсах. 7 5) Наследование на языке java Наследуемый класс – подкласс (subclass), класс от которого наследуется – суперкласс (superclass). Смысл protected такой же. Вариант программы с дополнительным классом для задания main. class Record // это суперкласс { protected int min,sec; public void Init(int m,int s) { min=m; sec=s; } public int Numbersec() { return min*60+sec; } } class Sprint extends Record // extends наследует (расширяет) – это подкласс { private int dec; public void Putdec(int d) { dec=d; } public int Numberdec() { int k; k=min*60+sec; return k*10+dec; } } public class WorkSport // класс для main public файл WorkSport.java { public static void main (String args[] ) { int p; Record a=new Record(); // объект Record a.Init(2, 40); p=a.Numbersec(); System.out.printf("%d\n ", p); 8 Sprint b=new Sprint(); // объект Sprint b.Init(1, 10); // вызов наследуемого метода; // b.min=5; - ошибка вызов protected вне наследуемого класса b.Putdec(6); p=b.Numberdec(); System.out.printf("%d\n ", p); } } 6) Перегрузка методов и явное указание класса вызываемого метода Возможна перегрузка метода из базового класса в производном классе. Пример – переопределение Init в Sprint class Record { public: void Init (int m,int s); int Numbersec(); protected: int min; int sec; }; int Record::Numbersec() { return min*60+sec; } void Record::Init(int m,int s) { min=m; sec=s; } class Sprint : public Record { public: void Init(int m,int s, int d); int Numberdec(); private: int dec; }; // перегрузка void Sprint::Init(int m,int s, int d) { min=m; sec=s; 9 dec=d; } int Sprint::Numberdec() { int k; k=Numbersec(); return k*10+dec; } int main(int argc, char* argv[]) { int m,n; Record x; x.Init(4,36); // min=4 sec=36 Sprint z; z.Init(1,8,6); // min=1 sec=8 dec=6 } Init(int m,int s,int d) в Sprint перекрывает наследуемый метод Init(int m,int s) в Record, не работает: int main(int argc, char* argv[]) { Sprint z; z.Init(1,8); // неправильное число аргументов ......... На Java перекрытия нет, работают обе функции, наследуемая и определенная в классе. Для вызова метода другого класса в C++ явно указывается принадлежность этому классу. z.Record::Init(5,8); // min=5 sec=8 dec не определено Вариант Init класса Sprint с вызовом Init базового класса. void Sprint::Init(int m,int s, int d) { Record::Init(m,s); // вызов метода из другого класса dec=d; } Возможна перегрузка метода в производном классе с такими же параметрами как в базовом классе. Добавлен метод: void Sprint::Init(int m,int s) { min=m; sec=s; 10 dec=1; } int main(int argc, char* argv[]) { Sprint z; z.Init(1,8,6); // min=1 sec=8 dec=6 вызов собственного метода z.Init(1,8); // вызов второго собственного метода Перегрузка методов производного класса в java class Record { protected int min,sec; public void Init(int m,int s) { min=m; sec=s; } public int Numbersec() { return min*60+sec; } } class Sprint extends Record { private int dec; public void Putdec(int d) { dec=d; } public int Numberdec() { int k; k=min*60+sec; return k*10+dec; } public void Init(int m,int s,int d) { min=m; sec=s; dec=d; } } 11 public class WorkSport { public static void main (String args[] ) { int p; Record a=new Record(); a.Init(2, 40); p=a.Numbersec(); System.out.printf("%d\n ", p); Sprint b=new Sprint(); b.Init(1, 10,5); p=b.Numberdec(); System.out.printf("%d\n ", p); } } В java перегруженный метод Init(int m,int s,int d) в Sprint не перекрывает наследуемый метод Init(int m,int s) из Record Sprint b=new Sprint(); b.Init(1, 10,5); Sprint c=new Sprint(); c.Init(2, 15); // вызов наследуемой функции из Record с двумя аргументами Вариант Init класса Sprint с вызовом наследуемого метода из Record public void Init(int m,int s,int d) { super.Init(m,s); // вызов метода базового класса (аналог Record::Init(m,s) на C++ dec=d; } Если в Sprint нет перегруженного метода из Record Init(int m,int s) с двумя аргументами в Java можно записать Init(m,s); без super. Понятно, где брать Init с двумя аргументами. 7) Конструкторы в производных классах Конструкторы не наследуются. Правила работы с конструкторами производного класса. Если в базовом классе есть конструктор без параметров, созданный в классе или сгенерированный по умолчанию, при создании объектов производного класса сначала вызывается конструктор базового класса. При вызове деструктора, наоборот, сначала вызывается деструктор производного класса, потом базового. Варианты для конструкторов. Примеры для C++, на Java одинаково. 1. В базовом и производном классе нет конструкторов. 12 Создаются пустые конструкторы в базовом и производном классе. int main(int argc, char* argv[]) { // вызов пустых конструкторов по умолчанию Record x; // min, sec не определены Sprint z; // min,sec,dec не определены } 2. В базовом классе создан конструктор без параметров, в производном конструктор отсутствует. class Record { private: int min,sec; public: Record(); ......... }; Record::Record() { min=2; sec=1; } class Sprint : public Record { private: int dec; public: ........ }; int main(int argc, char* argv[]) { Record x; // вызов конструктора без параметров min=2, sec=1 Sprint z; // вызов базового конструктора Record min=2, sec=1, dec не определен } 3. В базовом классе конструктор отсутстивует, в производном создан без параметров class Record { private: int min,sec; 13 public: ......... }; class Sprint : public Record { private: int dec; public: Sprint(); ........ }; Sprint::Sprint() { min=3; dec=2; } int main(int argc, char* argv[]) { Record x; // пустой min, sec не определены Sprint z; // min=3 dec=2 , sec – не определен } 4. В базовом и производном классах есть конструкторы без параметров. class Record { private: int min,sec; public: Record(); ......... }; Record::Record() { min=5; sec=4; } class Sprint : public Record { private: int dec; public: Sprint(); 14 ........ }; Sprint::Sprint() { min=3; dec=2; } int main(int argc, char* argv[]) { Record x; // min=5 sec=4 Sprint z; // min=3 dec=2 sec=4 – вызов базового конструктора } 5. В базовом есть конструктор без параметров, в производном с параметрами. class Record { private: int min,sec; public: Record(); ......... }; Record::Record() { min=1; sec=2; } class Sprint : public Record { private: int dec; public: Sprint(int d); ........ }; Sprint::Sprint(int d) { dec=d; } int main(int argc, char* argv[]) { 15 Record x; // min=1 sec=2 Sprint z(5); // min=1 sec=2 dec=5 // сначала вызывается конструктор базового класса } 6. Если в базовом классе есть только конструктор с параметрами и в производном создается конструктор с параметрами, то базовый конструктор должен быть явно вызван. class Record { private: int min,sec; public: Record(int m,int s); ......... }; Record::Record(int m,int s) { min=m; sec=s; } class Sprint : public Record { private: int dec; public: Sprint(int m,int s,int d); ........ }; Sprint::Sprint(int m,int s,int d) // ошибка, нет базового конструктора { min=m; sec=s; dec=d; } Sprint::Sprint(int m,int s, int d) :Record(m,s) // вызов базового конструктора в заголовке ! { dec=d; } int main(int argc, char* argv[]) { Record x(1,4); // min=1 sec=4 Sprint z(1,2,5); // min=1 sec=2 dec=5 16 } Java: package lab6_2; class Record { protected int min,sec; public Record(int m,int s) { min=m; sec=s; } } class Sprint extends Record { int dec; public Sprint(int m,int s,int d) { super(m,s); // вызов конструктора базового класса dec=d; } } public class lab6 { public static void main (String args[] ) { Record a=new Record(7,8); Sprint b=new Sprint(9,10,11); } } 8) Перегрузка оператора присваивания для производного класса на C++ Объектам базового класса можно присваивать объекты как базового так и производных классов, при этом происходит копирование всех полей. Объектам производного класса можно присвоить только объекты производного класса (нет значений дополнительных полей) int main(int argc, char* argv[]) { int m,n; Record x,y; 17 x.Init(4,36); // min=4 sec=36 y=x; // y min=4 sec=36 Sprint z,w; z.Init(1,8,6); // min=1 sec=8 dec=6 w=z; // w min=1 sec=8 dec=6 x=z; // x min=1 sec=8 w=y; // Ошибка не определено y.dec } На C++ возможна перегрузка оператора присваивания, аналогично +. class Sprint : public Record { public: void operator =(Record b); // void ! private: int dec; }; void Sprint::operator =(Record b) // перегрузка в классе Sprint { this->min=b.Getmin(); this->sec=b.Getsec(); // this->min=b.min; // ошибка ! // min – protected, но b объект базового класса, созданный // в производном не имеет доступа ни к private ни к protected this->dec=0; // задание значений недостающему полю } int main(int argc, char* argv[]) { Record x; x.Init(3,8); Sprint z; z=x; // min=3 sec=8 dec=0 } 9) Библиотека ввода-вывода на C++ Подключение библиотеки: #include cin – встроенный объект библиотеки ввода (входной поток связан с клавиатурой аналог scanf) cout – встроенный объект библиотеки вывода связан с экраном (printf) Перегруженный операторы << , >> для символьных величин – это логические сдвиги. 18 << - вставка в выходной поток - ввод с консоли >> - извлечение из входного потока - вывод на экран #include "stdafx.h" #include #include using namespace std; //--------------------------------------------------------------------------int _tmain(int argc, _TCHAR* argv[]) { char a,b,c; a='1'; // 0011 0001 '1' b=a << 2; // 1100 0100 'Д' логический сдвиг влево слева char c=a >>1; // 0001 1000 логический сдвиг вправо слева char // перегрузка << для вывода cout << "abc\n"; int d,e; d=45; e=67; cout <> ,<< для классов #include "stdafx.h" #include #include using namespace std; class Record { public: friend void operator << (ostream &o,Record r); friend Record operator >> (istream &i,Record &r); protected: int min; int sec; }; void operator << (ostream &o,Record r) { cout << r.min << " " << r.sec; } Record operator >> (istream &o,Record &r) { cin >> r.min >> r.sec; return r; } class Sprint : public Record { public: friend void operator << (ostream &o,Sprint r); friend Sprint operator >> (istream &i,Sprint &r); private: int dec; }; void operator << (ostream &o,Sprint r) { 21 cout << r.min << " " << r.sec<<" " <> (istream &o,Sprint &r) { cin >> r.min >> r.sec>>r.dec; return r; } int _tmain(int argc, _TCHAR* argv[]) { Record a; cin>>a; cout << a; Sprint b; cout << '\n'; cin>>b; cout << b; return 0; } Файловый ввод-вывод #include "stdafx.h" #include #include using namespace std; class Record { public: void Load(string Name); void Save(string Name); protected: int min; int sec; }; void Record::Load(string Name) { ifstream fin; // файловый ввод fin.open(Name.c_str()); // перевод в массив char fin >> min>>sec; fin.close(); } 22 void Record::Save(string Name) { ofstream fout; // файловый вывод fout.open(Name.c_str()); fout << min<<" "<> min>>sec>>dec; fin.close(); } void Sprint::Save(string Name) { Record::Save(Name); // вызов метода базового класса запись min,sec b закрытие файла ofstream fout; fout.open(Name.c_str(),ios::app); // ios::app – режим дополнения дозапись dec fout <<" " << dec; fout.close(); } int _tmain(int argc, _TCHAR* argv[]) { Record a; a.Load("rec.txt"); a.Save("rec1.txt"); Sprint b; b.Load("spr.txt"); b.Save("spr1.txt"); return 0; } rec.txt 2 45 23 spr.txt 2 57 8 На Java можно вывести объекты целиком, переводя их в string, перегрузив встроенный метод toString, имеющийся для всех объектов. Пример вывода объекта в Java class Record { protected int min,sec; public Record(int m,int s) { min=m; sec=s; } public String toString() { return min+" "+sec; } } public static void main (String args[] ) { Record a=new Record(7,8); System.out.printf("%s",a.toString()); } 24
«Наследование. Производные классы в C++, Java» 👇
Готовые курсовые работы и рефераты
Купить от 250 ₽
Решение задач от ИИ за 2 минуты
Решить задачу
Найди решение своей задачи среди 1 000 000 ответов
Найти

Тебе могут подойти лекции

Смотреть все 588 лекций
Все самое важное и интересное в Telegram

Все сервисы Справочника в твоем телефоне! Просто напиши Боту, что ты ищешь и он быстро найдет нужную статью, лекцию или пособие для тебя!

Перейти в Telegram Bot