Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_ООП_ИС.doc
Скачиваний:
387
Добавлен:
09.02.2015
Размер:
612 Кб
Скачать
☆

Void funс (int I)

{ printf("\nbase::i =",i); };

};

class derived: public base

{

public:

Void funс (int I)

{ printf("\nder::i =",i); };

};

В данном случае внешне одинаковые функции void func (int) определены в базовом классе base и в производном классе derived.

В теле класса derived обращение к функции func(), принадлежащей классу base, может быть выполнено с помощью полного квалифицированного имени, явно включающего имя базового класса: base::func(). При обращении в классе derived к такой же (по внешнему виду) функции, принадлежащей классу derived, достаточно использовать имя func() без предшествующего квалификатора.

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

Void main(void) {

base B, *bp = &B;

derived D, *dp = &D;

base *pbd = &D;

bp->func(1); // Печатает : base::i = 1

dp->func(5); // Печатает : der::i = 5

pbd->func(4); // Печатает : base::i = 4

};

В программе введены три указателя на объекты разных классов. Следует обратить внимание на инициализацию указателя pbd. В ней адрес объекта производного класса (объекта D) присваивается указателю на объект его прямого базового класса (base *). При этом выполняется стандартное преобразование указателей, предусмотренное синтаксисом языка Си++. Обратное образование, т.е. преобразование указателя на объект базового класса в указатель на объект производного класса, невозможно (запрещено синтаксисом). Обращения к функциям классов base и derived с помощью указателей bp и dp не представляют особого интереса. Вызов pbd->func() требуется прокомментировать. Указатель pbd имеет тип base*, однако его значение - адрес объекта D класса derived.

Какая же из функций base::func() или derived::func() вызывает при обращении pbd->func()? Результат выполнения программы показывает, что вызывается функция из базового класса. Именно такой вызов предусмотрен синтаксисом языка Си++, т.е. выбор функции (не виртуальной) зависит только от типа указателя, но не от его значения. «Настроив» указатель базового класса на объект производного класса, не удается с помощью этого указателя вызвать функцию из производного класса.

Пусть в этом классе определена компонентная функция void show(). Доступ к функции show() производного класса возможен только с помощью явного указания области видимости:

имя_производного_класса::show();

либо с использованием имени конкретного объекта:

имя_объекта_производного_класса.show();

В обоих случаях выбор нужной функции выполняется при написании исходного текста программы и не изменяется после компиляции. Такой режим называется ранним или статическим связыванием.

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

class base

{

public: