Конструкторы, деструкторы и наследование
Конструкторы не наследуются. Если конструктор базового класса требует спецификации одного или нескольких параметров, конструктор производного класса должен вызывать базовый конструктор, используя список инициализации элементов.
Деструктору производного класса, напротив, не требуется явно вызывать деструктор базового класса. В деструкторе производного класса компилятор автоматически генерирует вызовы базовых деструкторов.
Виртуальные функции
Член-функция базового класса может быть переопределена в производных классах и вызываться с помощью указателя или ссылки на базовый класс, которые ссылаются на объект производного класса. Иными словами, в базовом и производном классах могут быть функции с одинаковыми именами и даже с одинаковыми списками параметров. Вызываться будет член-функция того класса, которому принадлежит объект, чей адрес находится в указателе на базовый класс или на который ссылается ссылка на базовый класс. Следует еще раз подчеркнуть, что, например, имеется указатель на базовый класс, а адрес в него может быть занесен объекта производного класса. И тогда с помощью данного указателя будет вызвана член-функция именно этого производного класса из нескольких функций с одинаковыми именами.
Для того чтобы функцию с каким-то именем объявить виртуальной, нужно в базовом классе описать ее в иде:
Virtual тип_результата имя-функции(параметры).
В производных классах перед виртуальной функцией слово virtual можно не писать.
Виртуальная функция должна быть обязательно определена в базовом классе или хотя бы описана как чистая виртуальная функция
virtual тип_результата имя-функции()=0;.
Чистая виртуальная функция используется в т.н. абстрактных классах, которые будут рассмотрены позже.
Если в производном классе виртуальная функция не определена, то автоматически вызывается виртуальная функция из базового класса.
Следует помнить, что виртуальная функция не может быть friend и static.
Пример 1.
#include<stdio.h>
class A
{
рrotected:
int x;
public:
virtual void get_info()
{
puts(“Работает функция базового класса”);
puts(“Введите х=”)
scanf(“%i”, &x);
}
};
class B: public A
{
char* name;
public:
void get_info() // virtual можно не писать
{
name=new char[12];
puts(“Работает функция производного класса”);
puts(“Введите имя”);
fflush(stdin);
scanf(“%s”, name);
}
};
void main()
{
A*p1=new B;// Выделили память под объект класса В и адрес занесли в указатель //на/базовый класс.
p1→get_info();//Вызывается get_info() из класса В.
В w; //w – объект класса В.
A &pA=w;//pA – ссылка на базовый класс, но инициализирована объектом w класса //В.
pA.get_info();//Вновь вызывается get_info() из класса В, но уже с помощью ссылки.
}
Пример 2
#include<stdio.h>
class man
{
рrotected:
char* name;
public:
virtual void input()
{
name=new char[15];
puts(“Введите имя”);
fflush(stdin);
scanf(“%s”, name);
}
};
class student:public man
{
char*faculty;
public:
void input()//virtual можно не писать
{
faculty= name char[20];
puts(“Введите факультет”);
fflush(stdin);
scanf(“%s”, faculty);
}
};
class officer:public man
{
char* zvanie;
public:
void input()//virtual можно не писать
{
zvanie =new char[15];
puts(“Введите звание офицера”);
fflush(stdin);
scanf(“%s”, zvanie);
}
};
void main()
{
man x;
x.input();//Вызов из класса man
man*p1=new student;
/*p1 – указатель на базовый класс. В него занесли адрес, выделенный под объект класса student*/
p1→input();//Вызывается input()из класса student.
Student y;
p1=&y;//Адрес объекта класса student занесен в р1.
p1→input();//Вновь вызов input()из класса student.
officer z;
man &w=z;
/* w – ссылка на базовый класс man, но инициализирована объектом z производного класса officer */
w.input();//Вызов input()из класса officer.
}