C наследование метода Советник

Создание базового класса

Для решения этой задачи создадим базовый класс human, который будет описывать модель человека. В нем будут храниться имя, фамилия и отчество.

// human.h
#ifndef HUMAN_H_INCLUDED
#define HUMAN_H_INCLUDED

#include {amp}lt;string{amp}gt;
#include {amp}lt;sstream{amp}gt;

class human {
    public:
        // Конструктор класса human
        human(std::string last_name, std::string name, std::string second_name)
        {
            this-{amp}gt;last_name = last_name;
            this-{amp}gt;name = name;
            this-{amp}gt;second_name = second_name;
        }

        // Получение ФИО человека
        std::string get_full_name()
        {
            std::ostringstream full_name;
            full_name {amp}lt;{amp}lt; this-{amp}gt;last_name {amp}lt;{amp}lt; " "
                {amp}lt;{amp}lt; this-{amp}gt;name {amp}lt;{amp}lt; " "
                {amp}lt;{amp}lt; this-{amp}gt;second_name;
            return full_name.str();
        }

    private:
        std::string name; // имя
        std::string last_name; // фамилия
        std::string second_name; // отчество
};

#endif // HUMAN_H_INCLUDED

Теперь создайте новый класс student, который будет наследником класса human. Поместите его в файл student.h.

// student.h
#ifndef STUDENT_H_INCLUDED
#define STUDENT_H_INCLUDED

#include "human.h"
#include {amp}lt;string{amp}gt;
#include {amp}lt;vector{amp}gt;

class student : public human {
    public:
        // Конструктор класса Student
        student(
            std::string last_name,
            std::string name,
            std::string second_name,
            std::vector{amp}lt;int{amp}gt; scores
        ) : human(
            last_name,
            name,
            second_name
        ) {
            this-{amp}gt;scores = scores;
        }

        // Получение среднего балла студента
        float get_average_score()
        {
            // Общее количество оценок
            unsigned int count_scores = this-{amp}gt;scores.size();
            // Сумма всех оценок студента
            unsigned int sum_scores = 0;
            // Средний балл
            float average_score;

            for (unsigned int i = 0; i {amp}lt; count_scores;   i) {
                sum_scores  = this-{amp}gt;scores[i];
            }

            average_score = (float) sum_scores / (float) count_scores;
            return average_score;
        }

    private:
        // Оценки студента
        std::vector{amp}lt;int{amp}gt; scores;
};
#endif // STUDENT_H_INCLUDED

https://www.youtube.com/watch?v=ytpress

Функция get_average_score вычисляет среднее арифметическое всех оценок студента. Все публичные свойства и методы класса human будут доступны в классе student.

// Конструктор класса Student
student(
    // аргументы конструктора текущего класса
) : human(
    // инициализация конструктора родительского класса
) {
    // инициализация конструктора текущего класса
}
// Конструктор класса Student
student(
    std::string last_name,
    std::string name,
    std::string second_name,
    std::vector{amp}lt;int{amp}gt; scores
) : human(
    last_name,
    name,
    second_name
) {
    this-{amp}gt;scores = scores;
}

Список оценок студента хранится в векторе.

Реализуем пользовательский интерфейс для работы с классом student.

// main.cpp

#include {amp}lt;iostream{amp}gt;
#include {amp}lt;vector{amp}gt;

#include "human.h"
#include "student.h"

int main(int argc, char* argv[])
{

    // Оценки студента
    std::vector{amp}lt;int{amp}gt; scores;

    // Добавление оценок студента в вектор
    scores.push_back(5);
    scores.push_back(3);
    scores.push_back(2);
    scores.push_back(2);
    scores.push_back(5);
    scores.push_back(3);
    scores.push_back(3);
    scores.push_back(3);
    scores.push_back(3);

    // Создание объекта класса student
    student *stud = new student("Петров", "Иван", "Алексеевич", scores);

    // Вывод полного имени студента (используется унаследованный метод класса human)
    std::cout {amp}lt;{amp}lt; stud-{amp}gt;get_full_name() {amp}lt;{amp}lt; std::endl;
    // Вывод среднего балла студента
    std::cout {amp}lt;{amp}lt; "Средний балл: " {amp}lt;{amp}lt; stud-{amp}gt;get_average_score() {amp}lt;{amp}lt; std::endl;

    return 0;
}

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

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

Затем программа вычислияет средний балл студента и выводит его на экран. Этим занимается функция get_average_score, которую мы описали внутри класса student.

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

Нужно создать еще один класс, в котором будут храниться данные преподавателей. Дадим ему название — teacher. Как вы уже поняли, мы не будем описывать все методы этого класса с нуля, а просто унаследуем его от класса human. Тогда, не нужно будет реализовывать хранение имени, фамилии и отчества препода. Это уже есть в базовом классе human.

// teacher.h
#ifndef TEACHER_H_INCLUDED
#define TEACHER_H_INCLUDED

#include "human.h"
#include {amp}lt;string{amp}gt;

class teacher : public human {
    // Конструктор класса teacher
    public:
        teacher(
            std::string last_name,
            std::string name,
            std::string second_name,
            // Количество учебных часов за семетр у преподавателя
            unsigned int work_time
        ) : human(
            last_name,
            name,
            second_name
        ) {
            this-{amp}gt;work_time = work_time;
        }

        // Получение количества учебных часов
        unsigned int get_work_time()
        {
            return this-{amp}gt;work_time;
        }

    private:
        // Учебные часы
        unsigned int work_time;
};

#endif // TEACHER_H_INCLUDED

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

ПОДРОБНЕЕ:  Приказ 533 ростехнадзора 2014 Советник

Изменим содержимое файла main.cpp, чтобы проверить работу класса teacher.

#include {amp}lt;iostream{amp}gt;

#include "human.h"
#include "teacher.h"

int main(int argc, char* argv[])
{

    // Количество учебных часов преподавателя
    unsigned int teacher_work_time = 40;

    teacher *tch = new teacher("Васильков", "Петр", "Сергеевич", teacher_work_time);

    std::cout {amp}lt;{amp}lt; tch-{amp}gt;get_full_name() {amp}lt;{amp}lt; std::endl;
    std::cout {amp}lt;{amp}lt; "Количество часов: " {amp}lt;{amp}lt; tch-{amp}gt;get_work_time() {amp}lt;{amp}lt; std::endl;

    return 0;
}

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

Также, мы можем создать класс, который будет описывыть студента заочной формы обучения. Его мы унаследовали бы от класса student, добавив какие-либо дополнительные данные.

C наследование метода Советник

В класс human можно добавить еще больше свойств, которые будут описывать данные, имеющиеся у любого человека. Например, номер паспорта, дату рождения, прописку и место проживания.

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

Общее наследование

При общем наследовании порожденный класс имеет доступ к наследуемым членам базового класса с видимостью public и protected. Члены базового класса с видимостью private – недоступны.

Спецификация доступа внутри класса в порожденном классе вне класса
private
protected
public

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

Пример

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

#include {amp}lt;iostream{amp}gt;
using namespace std;
class student
{
protected:
char fac[20];
char spec[30];
char name[15];
public:
student(char *f, char *s, char *n);
void print();
};
class grad_student : public student
{
protected:
int year;
char work[30];
public:
grad_student(char *f, char *s, char *n, char *w, int y);
void print();
};
student::student(char *f, char *s, char *n)
{
strcpy_s(fac, strlen(f)   1, f);
strcpy_s(spec, strlen(s)   1, s);
strcpy_s(name, strlen(n)   1, n);
}
grad_student::grad_student(char *f, char *s, char *n, char *w, int y) :
student(f, s, n)
{
year = y;
strcpy_s(work, strlen(w) 1, w);
}
void student::print()
{
cout {amp}lt;{amp}lt; endl {amp}lt;{amp}lt; «fac: » {amp}lt;{amp}lt; fac {amp}lt;{amp}lt; » spec : « {amp}lt;{amp}lt; spec
{amp}lt;{amp}lt; » name : « {amp}lt;{amp}lt; name;
}
void grad_student::print() 
{
student::print();
cout {amp}lt;{amp}lt; » work : » {amp}lt;{amp}lt; work {amp}lt;{amp}lt; » year : « {amp}lt;{amp}lt; year;
}
int main() 
{
system(«chcp 1251»);
system(«cls»);
student s((char*)«МТ», (char*)»АМСП», (char*)»Сидоров Иван»);
grad_student stud((char*)«ПС», (char*)»УиТС», (char*)»Иванов Петр», (char*)»Метран», 2000);
student *p = {amp}amp;s;
p-{amp}gt;print();
grad_student *gs = {amp}amp;stud;
student *m;
gs-{amp}gt;print();
m = gs;
m-{amp}gt;print();
cin.get();
return 0;
}

ПОДРОБНЕЕ:  Наследование имущества иностранцами

Порожденный класс наследует все данные класса student (строка 13), имеет доступ к protected и public — членам базового класса. В новом классе добавлено два поля данных (строки 16, 17), и порожденный класс переопределяет функцию print() (строки 20, 39-43).

Конструктор для базового класса вызывается в списке инициализации (строка 29).

https://www.youtube.com/watch?v=upload

Результат выполненияФункция main создаёт объект класса student (строка 48) и объект класса grad_student (строка 49). Указателю p присваивается ссылка на объект класса student (строка 50), а указателю gs объект класса grad_student (строка 52). При этом функции вывода в строках 51 и 54 корректно отрабатываются для своего класса.

Но что происходит, когда мы присваиваем указателю класса student ссылку на объект класса grad_student (строка 55)? В этом случае происходит преобразование указателей, и в строке 56 вызывается уже функция print() класса student.

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

Неявные преобразования между порожденным и базовым классами называются предопределенными стандартными преобразованиями:

  • объект порожденного класса неявно преобразуется к объекту базового класса.
  • ссылка на порожденный класс неявно преобразуется к ссылке на базовый класс.
  • указатель на порожденный класс неявно преобразуется к указателю на базовый класс.

Частное наследование

class grad_student : private student
{…}
int main()
{

m = gs; // ошибка

}

Однако порождение private позволяет отдельным элементам базового класса с видимостью public и protected сохранить свою видимость в порожденном классе. Для этого необходимо

  • в части protected порожденного класса указать те наследуемые члены базового класса с видимостью protected, уточненные именем базового класса, для которых необходимо оставить видимость protected и в порожденном классе;
  • в части public порожденного класса указать те наследуемые члены базового класса с видимостью public, уточненные именем базового класса, для которых необходимо оставить видимость public и в порожденном классе.

Возможен и третий вариант наследования – с использованием модификатора доступа protected.

Модификатор наследования → public protected private
Модификатор доступа ↓
public public protected private
protected protected protected private
private нет доступа нет доступа нет доступа

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

C наследование метода Советник

Если у класса много свойств — их совсем не обязательно задавать в конструкторе. Для сохранения отдельных свойств класса используют set-функции. Например, для сохранения номера паспорта, можно создать публичный метод set_passport_number(std::string number), который будет принимать значение свойства и сохранять его в объекте, через переменную this.

Следующий урок — перегрузка функций в C .

Как базовый, так и производный классы могут иметь конструкторы и деструкторы.

Если и у базового и у производного классов есть конструкторы и деструкторы, то конструкторы выполняются в порядке наследования, а деструкторы – в обратном порядке. То есть если А – базовый класс, В – производный из А, а С – производный из В (А-В-С), то при создании объекта класса С вызов конструкторов будет иметь следующий порядок:

  • конструктор класса А
  • конструктор класса В
  • конструктор класса С.

Вызов деструкторов при удалении этого объекта произойдет в обратном порядке:

  • деструктор класса С
  • деструктор класса В
  • деструктор класса А.

Поскольку базовый класс «не знает» о существовании производного класса, любая инициализация выполняется в нем независимо от производного класса, и, возможно, становится основой для инициализации, выполняемой в производном классе. Поскольку базовый класс лежит в основе производного, вызов деструктора базового класса раньше деструктора производного класса привел бы к преждевременному разрушению производного класса.

КонструкторПроизводногоКласса (СписокФормальныхАргументов): КонструкторБазовогоКласса (СписокФактическихАргументов){ // тело конструктора производного класса }

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

https://www.youtube.com/watch?v=https:accounts.google.comServiceLogin

Конструктор производного класса не должен использовать все аргументы, часть предназначены для передачи в базовый класс (строка 29, см. код выше). В расширенной форме объявления конструктора производного класса описывается вызов конструктора базового класса.

Понравилась статья? Поделиться с друзьями:
Adblock
detector