Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на C / C++ / Лекции по объектно-ориентированному программированию (С++).doc
Скачиваний:
150
Добавлен:
02.05.2014
Размер:
226.82 Кб
Скачать

Конструкторы и деструкторы в иерархии классов.

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

Student :: Student (char*n, int a, float d)

{strcpy (name, n);

age = a;

dohod = d;}

Stipendia_Studenta :: Stip_Stud (char*n, int a, float d, float r_s, int m) :

Student (name, age, dohod ) // конструктор произв. класса содержит параметры базового класса.

{ kol_month = m;

razmer_stip = r_s;}

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

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

Student :: ~ Student ( )

{cout << “ \ n Деструктор базового класса”; }

Виртуальные функции.

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

# include <iostream.h>

class base // базовый класс

{public : void print ( )

{cout<< ” \ n Это класс base”;}

};

class proizv : public base

{public : void print ( )

{cout<< ” \ n Это класс proizv”;}

};

void mane ( )

{base B, *bp = &B; // тип указ. base

proizv D, *dp = &D; // тип указ. proizv

base *p = &D; // тип указателя base

bp → print ( ); // base

dp → print ( ); // proizv

p → print ( ); // base

}

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

Переопределенная функция вызывается в соответствии с классом указателя. Это раннее или статическое связывание.

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

Virtual тип_возвр_знач-я имя_функции (параметры)

сlass base {public : virtual void print ( )

{------ // ------ // ------ } } ; и т.д. см. предыдущую.

Результатом

// base

// proizv

// priz

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

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

Абстрактные классы.

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

Сontrol

ButtonBase ListControl

Button Check Radio List Combo

Box Button Box Box

Чтобы класс сделать абстрактным, нужно объявить одну или более его функций чисто виртуальными.

virtual тип_возвр_значения имя_ф (параметры) = Ø;

Напр.: virtual void print ( ) = Ø;

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

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

Shape

area ( )

# ifndef SHAPE_H

# define SHAPE_H // Опред. абстрактн. кл.

class shape {protected : double param; // Т.к. поле param должно быть доступно в производном классе, поэтому мы используем protected – спец. доступа //

public : shape (double); // конструктор базового класса

virtual double area ( ) = Ø; // чисто виртуальная функция

}; // конец определения базового класса.

class circle : public shape { double radius;

public: circle (double);

double area ( ); }

class triangle : public shape { double hight, dlina;

public: triangle (double, double);

double area ( ); }

class rectangle : public shape

{ double

void print_area (shape*ptr) {cout<<”Пл = ”<<ptr→area ( )<<endl;} // функция

main ( )

{circle c (5);

triangle t (4,32);

rectangle r (2,7);

print_area (& c); // площадь круга

print_area (& t); // площадь треугольника

Функция print_area одинаково вызывает разные функции area, которые являются методами разных классов в зависимости от объекта, на который будет указывать параметр print_area.

Это означает, что компилятор не может однозначно определить ссылку на функцию во время компиляции метода area, а компоновщик, соответственно разрешить эту ссылку. Поэтому ссылка не разрешена до выполнения программы. Окончательное связывание с нужным методом производит система исполнения. Это – позднее связывание.

Множественное наследование.

class произв_кл : квалификатор_доступа Баз_класс1;

квал_доступа Баз_класс 2,…

Например:

Баз.кл.А Баз.кл.В

Поле а Поле b

Методы Методы

Произв.кл.С

Поле с

Методы

// Файл заголовочн. abc.h

# ifndef abc_h

# define abc_h

// 1 класс

class A {protected: int a;

public: A (int);

virtual void Show ( );}; // конец определения класса

// 2 класс

сlass B {protected: int b;

public: B (int);

virtual void Show ( );};

class C: public A, public B {

int c;

public: c (int, int, int);

void show ( ); };

// Файл реализации abc.cpp.

# include “abc.h”

# include<iostream.h>

A :: A (int n) : a(n) { }

B :: B (int n) : b(n) { }

C :: C (int k, int l, int m)

A(k), B(l), C(m) { }

void A :: show ( ) {cout<<”a = ”<<a<<endl;}

void B :: show ( ) {cout<<”b = ”<<b<<endl;}

void C :: show ( ) {cout<<”a = ”<<a<<”b = ”<<b<<”c = ”<<c<<endl;}

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

// Демо-файл demo_abc.cpp

# include abc.h

void main ( )

{A *a = new A (1); // объекты базового класса

a → show ( );

delete a;

B *b = new B (2);

b → show ( );

delete b;

a = new C (3,4,5); // доступ к объектам произв.кл.

// производится с помощью указателя базового класса.

a → show ( );

delete a;

b = new C (6,7,8);

b → show ( );

delete b; }

Библиотека потоков языка СИ++ представляет собой набор классов для управления ввода/вывода. В сам язык СИ++ средства ввода/вывода не входят.

iostream.h