cpp-oop (823968), страница 7
Текст из файла (страница 7)
раздел5.4);• компоненты, добавляемые в теле производного класса.В функциональном смысле производные классы являются более мощными поотношению к базовым классам, так как, включая поля и методы базового класса, ониобладают еще и своими компонентами.Ограничение доступа к полям и функциям базового класса при наследованииосуществляется с помощью специальных описателей, определяющих вид наследования:class <Имя производного класса >:<Вид наследования><Имя базового класса>{<Тело класса>};где вид наследования определяется ключевыми словами: private, protected,public.Видимость полей и функций базового класса из производного определяется секцией,в которой находится объявление компонента и видом наследования (см.
табл. 2.1).ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»44Таблица 2.1. Видимость компонентов базового класса в производномВидОбъявление компонентов вВидимость компонентов внаследованиябазовом классепроизводном классеprivateне доступныprotectedprivatepublicprivateprivateне доступныprotectedprotectedpublicprotectedprivateне доступныprotectedprotectedpublicpublicprivateprotectedpublicЕсли вид наследования явно не указан, то по умолчанию принимается private.Однако хороший стиль программирования требует, чтобы в любом случае виднаследования был задан явно.Согласно таблице 2.1 самым простым является наследование вида public(общедоступное), однако при его применении следует помнить, что скрытые в секцииprivate компоненты базового класса в производном все равно недоступны.Соттветственно для обращения к скрытым полям базового класса должны использоватьсяметоды общедоступной или защищенных секций базового класса, например:class A{int x;public:void set_a(int ax){x=ax;}print_a(){cout<<x;}};class B:public A{int y;public:void set_b(int ax,int bx){ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»45set_a(ax);// доступ к скрытому полю xb=bx;}print_b(){print_a();// доступ к скрытому полю xcout<<y;}};Конструкторы и деструкторы производных классов. Как уже упоминалосьраньше в С++ конструкторы и деструкторы базового класса в производных классах ненаследуются. Однако если базовый класс содержит хотя бы один конструктор идеструктор, то производный класс также должен включать собственные конструктор идеструктор. При этом С++ поддерживает определенные правила взаимодействия междуэтими компонентами базовых и производных классов.При создании объектов производного класса предусмотрен автоматический вызовконструктора базового класса для инициализации его полей.
Однако следует помнить,что по умолчанию осуществляется вызов конструктора базового класса без параметров.Если такой конструктор в базовом классе отсутствует, то компилятор выдает сообщениеоб ошибке error C2512.Поскольку явный вызов конструктора базового класса в программе невозможен,чтобы передать этому конструктору аргументы для инициализации полей базового класса,следует:• добавить соответствующие параметры к собственным параметрам конструкторапроизводного класса;• вызвать конструктор базового класса в списке инициализации конструкторапроизводного класса, передав ему соответствующие аргументы.class A{int x;public:A(int ax):x(ax){} // конструктор базового классаОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»46};class B{int y;public:B(int ax,int ay):A(ax),y(ay){} // конструктор производного класса};При этом соблюдается строгий порядок конструирования полей базового ипроизводного классов: не зависимо от порядка указания в списке инициализации сначалавызывается конструктор базового класса, а затем – конструкторы полей, объявленных впроизводном классе.Пример 2.1.
Порядок работы конструкторов базового и производного классов.#include <iostream>using namespace std;class A{public:int a;A(int v):a(v){}void printa(){cout<<a<<endl;}};class B: public A{public:int b;B(int va,int vb):A(va),b(vb) {}void printb(void) {cout<<a<<" "<<b<<endl;}};class C: public B{public:int c;C(int va,int vb,int vc):B(va,vb),c(vc) {}void printc(void){cout<<a<<""<<b<<""<<c<<endl;}ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»47};void main(){A aa(10);// вызывается конструктор класса АB bb(10,100);//вызывается конструктор класса А, а затем – ВC cc(10,100,1000); // вызываются конструкторы классов А, В и Сaa.printa();bb.printb();cc.printc();system("pause");}Деструкторы (описанные в программе или созданные автоматически) будутвызываться в порядке, обратном порядку вызова конструкторов.Пример 2.2.
Проектирование классов с использованием наследования (классы Целоечисло и Вещественное число).Пусть требуется разработать классы для реализации объектов Целое число иВещественное число. Объект Целое число должен хранить длинное целое в десятичнойзаписи и уметь выводить его значение. Объект Вещественное число должен хранитьвещественное число, задаваемое в виде ccccc.dddddd, и его символьное представление.Он также должен уметь выводить свое значение на экран.Для обоих объектов необходимо предусмотреть возможность инициализации как вмомент объявления переменной, так и в процессе функционирования. Посколькувещественное число включает длинное целое как целую часть, класс для его реализацииможно наследовать от класса, реализующего длинное целое число (рис.
2.1).TlongTrealdlong numdlong drob,char *realTlong()~Tlong()setnum(),print()Treal()~Trealsetnumv()printr()Рис. 2.1. Наследование классов#include <locale.h>#include <stdlib.h>ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»48#include <iostream>#include <string.h>using namespace std;typedefunsignedlongdlong;// Класс Целое числоclass Tlong{public:dlong num;// числовое поле классаTlong(){}// неинициализирующий конструкторTlong(dlong an):num(an){} // конструктор~Tlong(){}// деструкторvoid print(void)// вывод значения поля{ cout<<" Целое число : "<<num<<endl; }void setnum(dlong an) // инициализации поля{ num=an; }};class// Класс Вещественное числоTreal: public Tlong{public:dlong drob;// дробная часть числаchar *real;// запись вещественного числаTreal()// инициализирующий конструктор без параметров{}real=NULL;Treal(char *st) :Tlong() // инициализирующий конструктор{setnumv(st); }~Treal()// деструктор{if (real!=NULL) delete [] real;}// вывод вещественного числаvoid printr();void setnumv(char * st);// инициализация полей класса};void Treal::setnumv(char * st){int l=strlen(st);ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»49char *ptr;real=new char[l+1];strcpy(real,st);ptr=strchr(real,'.');*ptr='\0';drob=dlong(atol(ptr+1));num=dlong(atol(real));*ptr='.';}void Treal::printr(){cout<<"Вещественное число: "<<real<<endl;cout<<"Целая часть: "; print();cout<<"Дробная часть: "<<drob<<endl;}void main (){setlocale(0,"russian");Treal a("456789.1234321"), // объект производного класса*pa=new Treal("456789.1234321"), // указательmask[3]= // инициализированный массив объектов{Treal("1748.5932"),Treal("4567.34321"),Treal("18689.9421")};a.printr();pa->printr();delete pa;for(int i=0;i<3;i++){cout<<"Элемент массива "<<(i+1)<<": "<<endl;mask[i].printr();}system("pause");}ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»50Управление видимостью компонентов базового класса в производном.Производный класс может получить доступ к компонентам секций protected и publicбазового класса даже при самом жестком виде наследования private. Для этогоиспользуют квалификатор доступа<Имя класса>::<Имя компонента>. Квалификаторследует поместить в ту же секцию, в которой необходимый компонент был описан вбазовом классе.Пример 2.3. Получение производным классом доступа к защищенным иобщедоступным компонентам базового класса при наследовании private.#include <iostream>using namespace std;class A{private:int x;protected:int y;public:int z;void print(void){cout<<"x = "<<x<<endl;cout<<"y = "<<y<<endl;cout<<"z = "<<z<<endl;}A(){x=20; y=30; z=50;}};class B: private A// все компоненты класса A не доступны в классе B{protected: A::y; /* защищенное поле класса A,объявляется доступным в классе B */public:A::z; /* общее поле класса A,объявляется доступным в классе B */B():A(){}void print(void){ОглавлениеИванова Г.С., Ничушкина Т.Н.