Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

МетодРисование_квадрата интерфейс 3 страница




Пример 3.6 Использование конструктора для инициализации полей объекта. Рассмотрим использование конструктора для инициализации полей объектов класса, описанного в примере 3.2, изменив доступность поля strl. Конструктор инициализирует поля объектов класса sstr и осуществляет действия, связанные с проверкой длины вводимой строки и коррекцией строки в случае несоответствия.

#tinclude <string.h>

#include <iostream.h>

#include <conio.h>

class sstr

{private: char strl[40];

public: int x,y;

void print(void) {

cout<< "содержимое общих полей: "<< endl;

cout<<"x= "<<x<<"y= "<<y<<endl;

cout<<"содержимое скрытых полей: "<< endl;

cout<<" strl = "<<strl<<endl;}

sstr(int vx,int vy,char *vs) //конструктор класса sstr

{ int len=strlen(vs); // проверка правильности задания длины

if(len>=40) {strncpy(strl,vs,40);strl[40]='\0';} else strcpy(strl,vs); x=vx;y=vy; }

};

void main() { clrscr();

//создание объекта класса sstr при наличии конструктора

sstr aa(200,150, "пример использования конструктора");

aa.print(); getch();

}

Как и любая другая компонентная функция, конструктор может быть переопределяемым, указывая соответствующие действия для различных списков параметров. Поэтому класс может иметь несколько конструкторов, позволяющих использовать разные способы инициализации объектов.

Пример 3.7 Использование переопределяемых конструкторов.

#include <string.h>

#include <iostream.h>

#include <conio.h>

class sstr

{private: char strl[40];

public: int x,y;

void print(void)

{cout<<" содержание полей: " <<endl;

cout<<" x= "<<x<<"y= "<<y<<endl;

cout<< " strl = "<<strl <<endl;}

sstr(void) // конструктор, определяющий поля по умолчанию

{strcpy(strl, "конструктор по умолчанию"); х=0;у=0; };

sstr(char *vs) // конструктор, получающий значение поля strl

{int len=strlen(vs);

if(len>=40) {strncpy(strl,vs,40);strl[40]='\0';}else strcpy(strl,vs); x=0; y=0; }

// значения х и у задаются по умолчанию

sstr(char *vs,int vx) // конструктор, получающий значения strl и х

{int len=strlen(vs);

if(len>=40) {strncpy(strl,vs,40);strl[40]='\0';} else strcpy(strl,vs); x=vx; y=0; }

// значение у задается по умолчанию

sstr(char *vs,int vx,int vy) // конструктор, получающий все значения

{int len=strlen(vs);

if(len>=40) {strncpy(strl,vs,40);strl[40]='\0';} else strcpy(strl,vs); x=vx;y=vy; }

};

void main()

{ clrscr();

sstr a0, a1(" пример конструктора 1 c x и у по умолчанию ");

sstr a2(" пример конструктора 2 су по умолчанию ",100);

sstr аЗ(" пример конструктора 3 со строкой по умолчанию ",200,150};

a0.print(); a1.print(); a2.print(); a3.print(); getch();}

 

Кроме того, иногда в конструкторах целесообразно использовать параметры, значение которых задается по умолчанию. В этом случае вместо нескольких переопределяемых конструкторов обычно можно описать один. Вернемся к предыдущему примеру и заменим все переопределяемые конструкторы одним.

Пример 3.8 Использование конструктора с аргументами по умолчанию.

#include <string.h>

#include <iostream.h>

#include <conio.h>

class sstr

{private: char strl[40]; public: int x,y;

void print(void)

{ cout<< " содержимое полей: ""<< endl;

cout<<" x= "<<x<<"y= "<<y<<endl;

cout<< " strl = "<<strl <<endl;}

sstr(char *vs,int vx,int vy);

/* прототип конструктора с параметрами, заданными по умолчанию */

};

sstr:: sstr(char vs=''строка по умолчанию ",int vx=80,int vy=90)

/* тело конструктора с параметрами, заданными по умолчанию */

{int len=strlen(vs);

if(len>=40) {strncpy(strl,vs,40); strl[40]='\0';} else strcpy(strl,vs); x=vx;y=vy;

}

void main() { clrscr();

sstr a0, a1(" x и у по умолчанию");

sstr a2(" у по умолчанию ", 100);

sstr а3("определяет все поля",200,150);

a0.print(); // выводит: х=80 у=90 strl= строка по умолчанию

al.print(); // выводит: х=80 у=90 strl= x и у по умолчанию

a2.print(); // выводит: х=100 у=90 strl= у по умолчанию

a3.print(); // выводит: х=200 у= 150 strl = определяет все поля

getch(); }

В конструкторах может использоваться специальная конструкция -список инициализации. Список инициализации отделяется от заголовка конструктора двоеточием и состоит из записей вида

<имя>(<список выражений>),

где в качестве имени могут фигурировать:

• имя поля данного класса,

• имя объекта другого класса, включенного в данный класс,

• имя базового класса.

Список выражений определяет значения, используемые для инициализации соответствующих объектов.

Конструктор со списком инициализации применяют для задания начальных значений объектам, в которых используются фиксированные (константные) и ссылочные поля, а также поля, являющиеся объектами других, ранее определенных классов. В последнем случае, если в определении класса не предусмотрен метод инициализации полей класса, список инициализации -это единственный способ вызвать конструктор объектного поля, так как явный вызов конструктора в C++ не возможен.

Иногда возникает необходимость создать объект, не инициализируя его поля. Такой объект называется неинициализированным и под него только резервируется память. Для создания подобного объекта следует предусмотреть неинициализирующий конструктор. У такого конструктора нет списка параметров и, обычно, отсутствует тело («пустой» конструктор). В этом случае при объявлении объекта с использованием такого конструктора значение полей объекта не определено.

Ниже приводится пример описания конструктора со списком инициализации и неинициализирующего конструктора для объектных и фиксированных полей.

Пример 3.9 Использование конструктора со списком инициализации и неинициализирующего конструктора.

#include <iostream.h>

#include <conio.h>

class integ

{ int num;

public:

void print(void) { cout<<" num= "<<num<<endl;}

integ(int v):num(v){} /* конструктор инициализирует поле num типа private с помощью списка инициализации */

integ(void){} // неинициализирующий конструктор

};

class obinteg

{ integ onum; // поле объектного типа

public: const int x,y,c; // поля фиксированного типа

void print(void)

{onum.print(); cout<<"x="<<x<<"y= "<<y<<"color ="<<с<<endl;}

obinteg(int va,int vx,int vy,int vc):onum(va),x(vx),y(vy),c(vc){}

/*конструктор инициализирует поле объектного типа и поля фиксированного типа списком инициализации*/

obinteg(void){} // неинициализирующий конструктор

void main()

{ integ aa(10); // инициализируемый объект

integ s1; // неинициализируемый объект

obinteg bb(20,40,100,13); // инициализируемый объект

obinteg s2; // неинициализируемый объект

cout<<"данные неинициализируемого объекта integ s1"<< endl;

s1.print(); // выводит случайные числа

cout<<"данные неинициализируемого объекта obinteg s2"<<endl;

s2.print(); // выводит случайные числа

cout << "данные объекта класса integ: "<<endl;

aa.print(); // выводит заданные значения

cout << "данные объекта с объектным полем integ: "<<endl;

bb.print(); // выводит заданные значения

getch();}

 

Не следует путать неинициализирующий конструктор с конструктором с параметрами, заданными по умолчанию, что возможно, если последний не имеет списка параметров (например, см. пример 3.7), так как в теле конструктора с параметрами по умолчанию задаются некоторые фиксированные значения полей.

Если в определении класса уже описан конструктор по умолчанию (с параметрами или без таковых), то его можно использовать вместо неинициализирующего. При этом необходимо помнить, что поля объекта, образованного с помощью такого конструктора, будут инициализированы фиксированными значениями. Определять же в одном и том же классе конструктор по умолчанию и неинициализирующий конструктор одновременно компилятор не позволяет, так как у них совпадает форма вызова.

При использовании в программах массивов объектов некоторого класса наличие неинициализирующего конструктора желательно, так как при создании массива объектов для каждого из его элементов автоматически вызывается конструктор класса, объектом которого является элемент.

Инициализацию полей массива объектов можно выполнять несколькими способами.

Первый способ - предусмотреть конструктор без параметров, который инициализирует поля объекта некоторыми значениями, формируемыми с помощью датчика случайных чисел. Автоматический вызов такого конструктора создаст массив с различными значениями. Однако такой способ в большинстве случаев не применим, так как значения полей объектов массива обычно должны задаваться определенным образом.

Второй способ - использовать конструктор класса, который инициализирует поля данными, вводимыми с клавиатуры. Данный способ требует ввода в момент определения массива объектов используемого класса, а это тоже не всегда удобно.

Пример 3.10 Использование предполагаемого копирующего конструктора.

#include <string.h>

#include <iostream.h>

#include <conio.h>

class child

{private: char *name; int age;

public: void print(void)

{cout<<" имя: "<<name; cout<<" возраст: "<<age<< endl;}

child(char *Name,int Age):name(Name),age(Age){}

};

void main()

{ clrscr();

child аа("Мария",6), bb("Евгений",5);

cout << " результаты работы программы: "<<endl;

aa.print(); // выводит: имя Мария возраст 6

bb.print(); // выводит: имя Евгений возраст 5

child dd=aa; // предполагается использование копирующего конструктора

dd.print(); // выводит: имя Мария возраст 6

getch(); }

По умолчанию предполагается конструктор:

child(const child & obj):name(obj.name),age(obj.age){)

В результате поля объекта aa без изменения копируются в поля dd.

Если же необходимо при копировании полей изменять их содержимое, следует явно определить в описании класса копирующий конструктор, предусмотрев действия по изменению значений всех или некоторых полей.

Пример 3.11 Явное определение копирующего конструктора.

#include <string.h>

#include <iostream.h>

#include <conio.h>

class intpole

{ int cif;

public: void print(void)

{cout<<"cif = "<<cif<<" "<< endl;}

intpole(int va) { cif=va;}

intpole(const lntpole& ob1) // копирующий конструктор

{ cif=ob1.cif*3;}

};

class obpole

{ int num; intpole intob; // объектное поле

public:

void print (void)

{intob.print(); cout<<" num= "<<num<<endl;}

obpole(int vn,int va):num(vn),intob(va){}

};

void main()

{ clrscr();

obpole aa(10,40);

cout << " результаты работы программы; "<<endl;

aa.print(); // выводит cif = 40 num = 10

obpole bb=aa; // активизируется копирующий конструктор

bb.print(); // выводится cif = 120 num = 10

getch(); }

В приведенном примере для класса obpole предполагается копирующий конструктор по умолчанию:

obpole(const obpole &obj):num(obj.num), intob(obj.intob){}

При инициализации объекта intob вызывается копирующий конструктор класса intpole, что приводит к инициализации соответствующего поля cif утроенным значением.

Кроме того, бывают случаи, когда поля объекта при копировании не изменяются, однако использование предполагаемого конструктора, автоматически создаваемого компилятором, может привести к непредсказуемым результатам.

Такая ситуация возникает, например, при вызове функции, получающей объект в качестве параметра, переданного «по значению». В этом случае, как известно, в памяти создается копия объекта, с которой должна работать функция. Для этого вызывается копирующий конструктор независимо от его наличия в описании класса. Автоматически генерируемый конструктор может не учесть особенностей объекта и его полей. Очень часто такие случаи происходят при работе с динамическими объектами и объектами, содержащими динамические поля (см. пример 3.30).

Деструкторы. При уничтожении объекта, так же, как при его конструировании, автоматически вызывается специальный метод - деструктор. Имя деструктора по аналогии с именем конструктора, совпадает с именем класса, но перед ним стоит символ «~» (префикс «тильда»). Деструктор определяет операции, которые необходимо выполнить при уничтожении объекта. Обычно он используется для освобождения памяти, выделенной под поля объекта данного класса конструктором. Деструктор не возвращает значения, не имеет параметров и не наследуется производными классами. Класс может иметь только один деструктор или не иметь ни одного. Так как деструктор - это функция, то он может быть виртуальным (см. пример 3.33). Однако отсутствие параметров не позволяет перегружать деструктор.

Деструктор вызывается неявно, автоматически, как только объект класса удаляется из памяти. Момент вызова определяется моделью памяти, выбранной для объекта (локальный, глобальный, внешний и т. д.). Если программа завершается с использованием функции exit, то вызываются деструкторы только глобальных объектов. При завершении программы, использующей объекты некоторого класса, функцией abort деструктор не вызывается. Однако, в отличие от конструктора, деструктор можно вызвать и явно.

Если в классе не объявлены конструктор и деструктор, то некоторые компиляторы автоматически производят их построение. При этом конструктор неявно используется для выделения памяти и размещения объекта после его описания, а деструктор - для корректного освобождения памяти после того, как имя объекта становится недействительным. В тех компиляторах, которые не производят автоматического построения конструкторов и деструкторов при их отсутствии, выдается диагностическое сообщение, требующее явного объявления этих компонентов класса.

Примечание. Если объект содержит указатель на некоторую динамически выделенную область памяти, то по умолчанию эта память не освобождается.

Пример 3.12 Определение в классе деструктора.

#include <iostream.h>

#include <string.h>

class din_string

{ char *str; // поле класса - указатель на строку

unsigned size;

public:

din_string(char *s, unsigned SIZE=100); // прототип конструктора

~din_string(); // прототип деструктора

void display() {cout <<str <<endl;}

};

din_string::din_string(char *s, unsigned SIZE) // конструктор

{str = new char [size = SIZE]; strcpy(str,s);}

din_string::~din_string() // описание деструктора вне класса

{delete [] str;}

void main()

{ din_string A ("Пример строки 1");

char ss [] = "Строка для динамического объекта";

din_string *р = new din_string(ss,sizeof(ss));

p->display():

delete p; // уничтожить объект - неявный вызов деструктора

A.display();} // деструктор А будет вызван после окончания программы

3.3. Наследование

Язык C++ поддерживает механизм наследования, являющийся одной из фундаментальных концепций ООП. Наследованием называют конструирование новых более сложных производных классов из уже имеющихся базовых посредством добавления полей и методов. Это - эффективное средство расширения функциональных возможностей существующих классов без их перепрограммирования и повторной компиляции существующих программ.

По определению компонентами производного класса являются все компоненты базового класса, за исключением конструктора, деструктора и компонентной функции, переопределяющей оператор равно (=), а также все компоненты, перечисленные в теле производного класса. Первое поле производного класса расположено после всех полей базового класса.

В функциональном смысле производные классы или потомки являются более мощными по отношению к исходным (базовым) классам или классам-родителям, так как, имея доступ ко многим функциям и полям базового класса, они обладают еще и своими компонентами.

Ограничение доступа к полям и функциям базового класса (родителя) осуществляется с помощью специальных описателей, определяющих вид наследования.

Определение производного класса (потомка) выполняется следующим образом:

class <имя производного класса >:

<вид наследования><имя базового класса>{<тело класса>};

где вид наследования определяется ключевыми словами: private, protected, public.

Видимость полей и функций базового класса из производного определяется видом наследования и представлена в табл. 3.1.

Если вид наследования явно не указан, то по умолчанию принимается private. Однако хороший стиль программирования требует, чтобы в любом случае вид наследования был задан явно.

Таблица 3.1. Видимость компонентов базового класса в производном

Вид наследования   Объявление компонентов в базовом классе Видимость компонентов в производном классе
private private protected public не доступны private private
protected private protected public не доступны protected protected
public private protected public не доступны protected public

 

Пример 3.13 Описание производного класса с видом наследования public.

#include <iostream.h>

#include <conio.h>

class A

{private: //защищенные (закрытые) компоненты класса

int numza;

public: // общедоступные (открытые) компоненты класса

int numoa;

void print(void)

{ cout<< "защищенное поле A = "<<numza<<endl;

cout<< "открытое поле A - "<<numoa<<endl;}

A()

{ numza=20; numoa=50;}

};

class B: public A /* открытое наследование - классу В доступны всеобщие компоненты класса А */

{private:

int numzb;

public:

void print (void)

{ cout<< "защищенное поле В = "<<numzb<<endl;

cout<< "общее поле A = ";

cout< <numoa< < endl;}

B() {numzb=100;}

};

void main()

{ clrscr();

A aa; В bb;

cout << "результаты работы: "<<endl;

aa.print(); // выводит: защищенное поле А = 20 открытое поле А = 50

bb.print(); // выводит: защищенное поле В = 100 общее поле А= 50

getch(); }

Производный класс может по отдельности изменять доступность компонентов секций protected и public базового класса даже при самом жестком режиме наследования private. Однако в этом случае следует помнить, что описание доступности поля нужно помещать в ту же секцию, в которой оно описано в базовом классе.

Пример 3.14 Описание производного класса с видом наследования private.

#include <iostream.h>

#include <conio.h>

class A

{private: int numza;

protected: int numpra;

public: int numoa;

void print(void)

{ cout<< "закрытое поле класса А = "<<numza<<endl;

cout<< "защищенное поле класса A= "<<numpra<<endl;

cout<< "открытое поле класса А = "<<numoa<<endl;}

A(){numza=20; numpra=30; numoa=50;}

};

class B: private A // все компоненты класса не доступны в классе B

{private: int numzb;

protected:

A::numpra; // защищенное поле класса A, объявляется доступным в классе B

public:

А:: numоа; // общее поле класса А, объявляется доступным в классе В

void print(void)

{ cout<<" закрытое поле класса В = "<<numzb<<endl;

cout<<" открытое поле класса А, доступное в В=";

cout<<numoa<<endl;

cout<< "защищенное поле класса А, доступное в В = ";

cout<<numpra<<endl; }

B(){numzb=100; }

void main()

{ clrscr();

A aa; В bb;

cout<< "результаты работы: "<<endl;

aa.print(); // выводит: 20 30 50

bb.prmt(); //выводит: 100 50 30

getch();}

Производный класс может стать базовым для какого-либо другого класса. Множество связанных по наследованию классов образует иерархию классов.

Работа с объектом производного класса может осуществляться через указатель, объявленный для базового класса. Это возможно благодаря стандартному преобразованию указателя на производный класс в указатель на базовый, предусмотренному синтаксисом языка C++. Однако в этом случае указатель настроен на базовый класс и, как отмечалось в § 1.6, при работе с полями и методами производных классов возможны проблемы видимости этих компонентов.

Конструкторы и деструкторы производных классов. В C++ конструкторы и деструкторы базового класса не наследуются в производных классах. Однако производный класс может иметь собственные конструктор и деструктор, поэтому C++ поддерживает определенные правила взаимодействия между этими компонентами базовых и производных классов, которые необходимо соблюдать при использовании механизма наследования.

При объявлении объектов производного класса предусмотрен автоматический вызов конструктора базового класса. Если конструктор базового класса имеет аргументы, то их значения должны быть переданы через дополнительные аргументы конструктора производного класса. При этом соблюдается строгий порядок конструирования объектов базового и производного классов: сначала создается объект базового класса и, возможно, его компоненты в порядке их объявления, а затем - объект производного класса.

Пример 3.15 Порядок работы конструкторов базового и производного классов.

#include <iostream.h>

#include <conio.h>

class A

{ int a;

public: int c1;

void print(void) {cout<<a<<" "<<c1<<endl;}

A(int v):a(v){c1=10;} //конструктор базового класса А

class B: public A

{ int b;

public:

void print (void) { cout<<b<<" "<<cl<<endl;}

B(int va,int vb):A(va),b(vb){} // конструктор класса В

};

class С: public В

{ int с; public:

void print(void) {cout<<c<<" "<<cl<<endl;}

C(int va,int vb,int vc):B(va,vb),c(vc){} // конструктор класса С

};

void main()

{ clrscr();

A aa(10), *pa; // вызывается конструктор класса A

В bb(10,100); //вызывается конструктор класса A, а затем – B

С cc(10,100,1000): // вызываются конструкторы классов A, B и C

bb.cl=25: // задание начальных значений общей компоненте cl

cc.с1=35;

cout << "результаты работы: "<<endl;

aa.print(); // выводит: 10 10

bb.print(); // выводит: 100 25

cc.print(); // выводит: 1000 35

ра=&аа; pa->print(); // выводит: 10 10

pa=&bb; /* указателю на объект базового класса присваивается адрес объекта производного класса и осуществляетсявызов компонентной функции */

pa->print(); // выводит: 10 25

ра=&сс:

pa->print(); // выводит 10 35

getch(); }

Отличие результатов вывода при обращении к компонентной функции print() непосредственно с использованием полного имени объекта и при обращении через указатель объясняется тем, что указатель настроен на базовый класс и внутренние поля производных классов ему не доступны. По той же причине происходит вызов метода print() базового класса. Для получения правильного результата необходимо использовать механизм сложного полиморфизма (см. § 3.4).

Деструкторы, если они необходимы в программе, будут вызываться в порядке, обратном порядку вызова конструкторов. Если деструктор не определен, то он создается по умолчанию и при необходимости освобождает память, отведенную под сам динамический объект. Однако при использовании динамических полей автоматического освобождения памяти не происходит, поэтому следует предусмотреть деструктор, который освобождал бы память, выделенную под динамические поля объекта используемого класса.

Пример 3.16 Проектирование классов с использованием наследования (классы Целое число и Вещественное число). Пусть требуется разработать классы для реализации объектов Целое число и Вещественное число.

Объект Целое число должен хранить длинное целое в десятичной записи, уметь выводить его значение и определять количество значащих цифр десятичной записи хранимого числа. Объект Вещественное число должен хранить вещественное число, задаваемое в виде ccccc.dddddd, и его символьное представление. Он также должен уметь выводить свое значение, определять количество цифр десятичной записи целой и дробной частей.

Для обоих объектов необходимо предусмотреть возможность инициализации как в момент объявления переменной, так и в процессе функционирования. Поскольку вещественное число включает длинное целое как целую часть, класс для его реализации можно наследовать от класса, реализующего длинное целое число (рис. 3.2).

#include <stdio.h>

#include <stdlib.h>

#include <iostream.h>

#include <string.h>

#include <conio.h>

typedef unsigned long dlong;

class Tlong. // Класс Целое число

{public:

dlong num; // числовое поле класса

Tlong() {cout<<"Неинициализирующий конструктор класса Tlong"<<endl;}

Tlong(dlong an) { cout<< "Конструктор класса Tlong"<<endl; setnum(an);}

void main ()

{clrscr();

cout<<"Введите число ccccc.dddddd"<<endl; cin>>s;

Treal a(s), *pa=new Treal("456789.1234321 "),mask[2J;

cout<< "ПРОСТОЙ ОБЪЕКТ ПРОИЗВОДНОГО КЛАССА "<<endl;

a.printr();

cout<<"Количество цифр целой части числа = "<<a.kolc()<<endl;

cout<<"Количество цифр дробной части числа = "<<a.dkolc()<<endl;

getch();

cout<<" УКАЗАТЕЛЬ НА ОБЪЕКТ ПРОИЗВОДНОГО КЛАССА "<<endl;

pa->printr();

cout<<"Количество цифр целой части числа = "<<pa->kolc()<<endl;

cout<<"Количество цифр дробной части числа "<<pa->dkolc()<<endl;

getch();

cout<<"МАССИВ ОБЪЕКТОВ ПРОИЗВОДНОГО КЛАССА "<<endl;

for(int i=0;i<2;i++)

{cout<<"Введите "<<(i+l)<< "число ccccc.dddddd"<<endl; cin>>s;

mask[i].setnumv(s); }

for(i=0;i<2;i++)

{ cout<< "Элемент массива "<<(i+1)<<": "<<endl;

mask[i].printr();} getch();}

 

Tlong   Treal
dlong num dlong drob, char *real
Tlong(), Tlong(dlong an), ~TIong(), setnum(), print(), kolc() Treal(), Treal(char *st), ~Treal, setnumv(), printr(), dkolc()

Рис. 3.2. Иерархия классов Целое число - Вещественное число

Множественное наследование. Язык C++ позволяет осуществлять наследование не только от одного, но и одновременно от нескольких классов. Такое наследование получило название множественного. При множественном наследовании производный класс включает произвольное количество базовых классов. Описание производного класса в этом случае выглядит следующим образом:

class <имя производного класса>:

<вид наследования><имя базового класса 1>, <вид наследования><имя базового класса 2>,




Поделиться с друзьями:


Дата добавления: 2014-12-08; Просмотров: 512; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.176 сек.