Помощничек
Главная | Обратная связь


Археология
Архитектура
Астрономия
Аудит
Биология
Ботаника
Бухгалтерский учёт
Войное дело
Генетика
География
Геология
Дизайн
Искусство
История
Кино
Кулинария
Культура
Литература
Математика
Медицина
Металлургия
Мифология
Музыка
Психология
Религия
Спорт
Строительство
Техника
Транспорт
Туризм
Усадьба
Физика
Фотография
Химия
Экология
Электричество
Электроника
Энергетика

Динамическое связывание в ООП (полиморфизм)



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

Статические поля

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

Свойства статических полей:

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

#include <iostream.h>

Class Example

{public:

static int value;//объявление в классе

};

int Example::value; //определение статического поля в глобальной области, по умолчанию инициализируется нулем.

// int Example::value=10; //пример инициализации произвольным значением

2) статические поля доступны как через имя класса, так и через имя объекта

Example object1, *object2;

cout<<Example::value<<object1.value<< object2->value;

 

3) на статические поля распространяется действие спецификаторов доступа, поэтому статические поля, описанные как private, нельзя изменить с помощью операции доступа к области действия; это можно сделать только с помощью статических методов;

4) память, занимаемая статическим полем, не учитывается при определении размера с помощью операции sizeof.

Статические методы

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

#include <iostream.h>

Class Simple

{public:

static int sum(int v1, int v2) {return v2+v1;}

};

Void main()

{cout<<Simple::sum(10,20)<<"\n"; //первый способ вызова функции

Simple s1;

cout<<s1.sum(10,20); //второй способ вызова функции

}

 

Дружественные классы

Дружественность – возможность использования метода двумя и более объектами различных классов, связанных отношениями общности.

Дружественные классы необходимы в том случае, если не связанным отношением родства классам необходим доступ к закрытым или защищенным секциям одного из них.

#include <iostream.h>

//не правильный вариант

class A

{double x;

public:

A() {x=3.14;}

};

class System: public A

{public:

void f() {cout<<x;} //доступ к переменной x закрыт

};

//правильный вариант

class A

{ friend class System;

double x;

public:

A() {x=3.14;}

};

class System

{public:

A obj;

void f() {cout<<obj.x<<endl;}

};

Свойства друзей:

1) отношение дружественности не наследуются, то есть, если A дружественен B, а C порожден от A, то это не означает, что C становится автоматически дружественным B;

2) свойство дружественности не транзитивно, то есть, если класс А дружественен классу В, а класс В – классу С, то А не становится автоматически дружественным классу С;

3) свойство дружественности не коммутативно, то есть, если A дружественен B, то это не означает, что B дружественен A.

Но при этом A можно объявить дружественным B.

Взаимодружественные классы

class A; //неполное объявление класса

class B

{ friend class A;

public:

void f(A* c1) {};};

class A;

{ friend class B;};

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

 

Контейнерные классы

Контейнерные классы – это классы, которые содержат в своем описании один или несколько объектов или указатели на объекты. В этом случае имеет место отношение «содержит».

//f1.h

#include <iostream.h>

class Tail

{int length;

public:

Tail(int n) {length=n;}

int GetTail() {return length;}

};

class Dog

{Tail tail;

public:

Dog(int n):tail(n) {};

void DisplayPar() {cout<<tail.GetTail()<<endl; return;}

};

//f1.cpp

#include "f1.h"

void main()

{ Dog d(20);

d.DisplayPar();

}

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

 

Динамическое связывание в ООП (полиморфизм)

Полиморфизм – это свойство ООП, при котором одно и тоже сообщение может вызывать различные действия на этапе выполнения.

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

Способность объектно-ориентированных языков автоматически определять тип объекта на этапе выполнения программы называется RTTI (run-time type identification – идентификация во время выполнения).

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

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

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

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

A* aobject; A

­

B* bobject; B

­

C* cobject; C

cobject=&аobject // так нельзя делать

aobject=&cobject.

Пример:

//f1.h

#include <iostream.h>

class Animal

{public:

/*virtual*/ char* speak() {return "";}

};

class Dog: public Animal

{public:

char * speak() {return "Gav!!!";}

};

//f1.cpp

#include "f1.h"

void sound(Animal& i)

{cout<<i.speak()<<endl;}

void main()

{ Dog Sharic;

sound(Sharic); //”” (на экран будет выведена пустая строка)

}

Решение проблемы – позднее связывание. Функцию speak() класса Animal достаточно объявить виртуальной, после чего компилятор запустит механизмы позднего связывания.

//f1.h

#include <iostream.h>

#include <string.h>

class Animal

{

protected:

char *pname;

public:

Animal(char *AnName)

{

pname=new char[strlen(AnName)+1];

strcpy(pname, AnName);

}

virtual char* speak() {return "";}

virtual char *name() {return pname;}

};

 

class Dog: public Animal

{

public:

Dog(char *name):Animal(name) {}

char *speak()

{

char *phrase;

phrase=strdup(pname); //дублирует строку, при этом вызывая функцию malloc()

return strcat(phrase," Say Gav! ");

}

virtual char *sit()

{

char *phrase; phrase=strdup(pname); return strcat(phrase," sits");

}

};

//f1.cpp

#include "f1.h"

void main()

{

Animal* p[2]={new Animal("a"), new Dog("Sharic")};

cout<<p[0]->speak()<<endl; //выведет на экран пустую строку

cout<<p[1]->speak()<<endl; //выведет на экран строку “Sharic Say Gav!”

//cout<<p[1]->sit()<<endl; //ошибка компиляции: 'sit' : is not a member of 'Animal'

cout<<((Dog*)p[1])->sit()<<endl;

}

 




Поиск по сайту:

©2015-2020 studopedya.ru Все права принадлежат авторам размещенных материалов.