Код программы и все, что могут по нему спросить
#include<iostream.h>
#include "string.h"
class A{ // cуперкласс
public:
A(){a=0; cout<< "A a="<<a<<endl;};
~A(){cout << "~A"<<endl;};
virtual int Ma() // virtual для замещения функции
{return a;}
protected:
int a;
};
class B:public A{ // подкласс
public:
B(){a=1; cout<< "B a="<<a<<endl;}
~B(){cout << "~B"<<endl;};
virtual int Ma() //замещение функции
{return a;}
};
class C:public B{ // подкласс
public:
C(){a=2;cout<< "C a="<<a<<endl;}
~C(){cout << "~C"<<endl;};
virtual int Ma() //замещение функции
{return a;}
};
int main() {
A *a; // а - полиморфная переменная, т.е. указатель на абстрактный базовый тип... В нашем случае, мы говорим что а - указатель на объект класса А
a = new A; // - создание динамического объекта
cout<<a->Ma()<<endl;
cout<<" создать объект B " <<endl;
a = new B; // Выполняется принцип подстановки. Функция new выделяет память, размера B, под объект класса B, и возвращает нам адрес ячейки памяти, где она выделилась... т.е. мы присваиваем указателю а адрес ячейки, и теперь а - это указатель на ячейку памяти, в которой хранится объект B...
cout<<a->Ma()<<endl; //(Мы через указатель общаемся с классом В и вызываем функцию Ма()) полиморфный вызов – тут происходит замещение т е используется функция Ма не та, что описана в суперклассе А, а та, что описана в подклассе В
Более подробное разъяснение:
Мы заходим в ячейку памяти, на которую указывает а и берем там объект, который там лежит, и на нем выполняем функцию Ма(), в данном случае мы заходим в ячейку, на которую указывает а, и в которой лежит объект b, затем через объект выполняем функцию.
Функция Ма() описана в суперклассе (в остальных она лишь переопределена), поэтому при ее вызове мы сначала обращаемся в суперкласс, где есть виртуальная функция. Мы смотрим, на что указывает указатель а? в нашем случае он указывает на ячейку с объектом В, значит мы переходим в класс В и там выполняем эту функцию; то есть происходит замещение функции (полиморфный вызов).
Замещение - это возможность функции по-разному реагировать на обращение к ней, т.е. при обращении к ней она будет по-разному выполнятся, в зависимости, на что указывает указатель а.
cout<<" создать объект C " <<endl;
a = new C; // выполнение принципа подстановки
cout<<a->Ma()<<endl;
// C* c = dynamic_cast <C*> (a); // проверяет на соответствие полиморфную переменную и указанный в этой строке тип.
// if(c!= NULL)
// {cout<<"a pointer C"<<endl; }
cout<<" вызов диструктора объекта с " <<endl;
{
C c;
} // вызов диструктора объекта с
cout<< "выход из программы"<<endl;
return 0;
}
Принцип подстановки (формулировка).
Принцип подстановки – это принцип, позволяющий вместо объектов (а) суперкласса (А), подставить объекты (в,с…) подклассов (В,С…) не зависимо от уровня иерархии и без видимых изменений поведения.
Этот принцип выполняется в строках a = newB; и a = newC; т.к. здесь вместо объектов суперкласса А, подставляются объекты классов B и С.
Последовательность создания и разрушения объектов.
Объекты создаются последовательно таким образом, что первым создается всегда объект суперкласса, а затем уже объекты наследуемых классов. Например:
При создании объекта типа В у нас сначала идет обращение к конструктору объекта из суперкласса А, а уже затем программа обращается к конструктору объекта подкласса В.
Соответственно, при создании объекта класса С, происходит все тоже самое в том же порядке, только после конструирования объекта класса В еще конструируется объект класса С.
Удаление объектов: допустим a=newC;
чтобы удалить при виртуальном деструкторе, нужно написать
delete a; тогда у нас выполнится ~C() ~B() ~A()
если мы напишем delete a; при не виртуальном деструкторе, то у нас удалится только объект a. Чтобы удалить при не виртуальном деструкторе, нужно написать delete (C*) a; - это динамическая типизация, т.е. мы сначала приводим а к типу с и сразу удаляем с, а не последовательно...Т.е. при не виртуальном деструкторе надо писать delete (C*) a; и тогда всё удалится корректно
Замещение.
Замещение - это возможность функции по-разному реагировать на обращение к ней, т.е. при обращении к ней она будет по-разному выполнятся, в зависимости, на что указывает указатель а.
(Замещаемая функция способна обеспечить полиморфное поведение в соответствии с типом, который переменная имеет при вызове функции.)
Виртуальная функция - функция класса, которая может быть переопределена в классах-наследниках так, что конкретная реализация метода будет определяться во время исполнения.
Полиморфизм
Полиморфизм - возможность для объектов разных классов, связанных наследованием, по-разному реагировать при обращении к одной и той же функции-элементу
Утечка памяти и методы ее устранения.
Утечка памяти- неконтролируемый процесс уменьшения объема оперативной памяти компьютера, связанный с ошибками в работающих программах, вовремя не освобождающих ненужные участки памяти или с ошибками системных служб контроля памяти
Методы устранения:
· Отказ от использования динамических переменных
· «Сборка мусора»(своевременное очищение ненужных участков памяти)