МЕНЮ


Фестивали и конкурсы
Семинары
Издания
О МОДНТ
Приглашения
Поздравляем

НАУЧНЫЕ РАБОТЫ


  • Инновационный менеджмент
  • Инвестиции
  • ИГП
  • Земельное право
  • Журналистика
  • Жилищное право
  • Радиоэлектроника
  • Психология
  • Программирование и комп-ры
  • Предпринимательство
  • Право
  • Политология
  • Полиграфия
  • Педагогика
  • Оккультизм и уфология
  • Начертательная геометрия
  • Бухучет управленчучет
  • Биология
  • Бизнес-план
  • Безопасность жизнедеятельности
  • Банковское дело
  • АХД экпред финансы предприятий
  • Аудит
  • Ветеринария
  • Валютные отношения
  • Бухгалтерский учет и аудит
  • Ботаника и сельское хозяйство
  • Биржевое дело
  • Банковское дело
  • Астрономия
  • Архитектура
  • Арбитражный процесс
  • Безопасность жизнедеятельности
  • Административное право
  • Авиация и космонавтика
  • Кулинария
  • Наука и техника
  • Криминология
  • Криминалистика
  • Косметология
  • Коммуникации и связь
  • Кибернетика
  • Исторические личности
  • Информатика
  • Инвестиции
  • по Зоология
  • Журналистика
  • Карта сайта
  • Объективное программирование

    =

    приводит к тому, что объект инициализируется путем побайтного

    копирования содержимого другого объекта без вызова конструктура. K таким

    же объектам относятся объекты - формальные параметры функций, которые

    инициализируются копиями фактических параметров.

    Eсли функция возвращает объект, то оператор return также выполняет

    копирование объекта - операнда в объект назначения.

    Taкое копирование не корректно в том случае, если объекты содержат

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

    случае можно воспъльзоваться специальным конструктором копирования,

    параметром котрого является неявная ссылка на объект - источник, а this

    указывает на объект приемник. Будучи определенным, он вызывается во всех

    вышеперечисленных случаях копирования объектов один в другой.

    Пример корректного конструктора копирования для класса строк имеет

    вид:

    class string

    {

    char *s; // Ссылка на строку

    int sz; // Длина строки

    public: string(string&);// Конструктор копирования

    }; // создает копию строки в динамической

    // памяти для объекта - приемника

    string::string(string& right)

    {

    s = new char[right->sz];

    strcpy(s,right->s);

    }

    Лекция 6. Производные классы

    ---------------------------

    6.1 Вложенные классы

    -------------------

    Понятие производного класса вводит в систему классов принцип

    иерархии. Действительно, если определен класс объектов с достаточно

    общими свойствами то объект данного класса желательно включать в качестве

    одного из элементов в объекты других классов. Существует два способа

    такого включения, каждый из них имеет

    собственные цели и особенности.

    Первый случай представляет собой обычный способ построения

    инрархической структуры данных, когда объект старого класса является одним

    из элементов данных "приватной" части нового класса.

    Он имеет собственное имя (именован), по которому к нему можно обращаться

    как к объекту. В элементах-функциях нового класса можно

    использовать элементы-функции и операции для объекта старого

    класса. Рассмотрим в качестве примера класс man - информация о

    человеке, включающая в себя даты рождения и поступления на работу.

    class man

    {

    char name[20]; // Другие элементы класса

    char *address;

    dat dat1; // Дата рождения

    dat dat2; // Дата поступления на работу

    public:

    void newadr(); // Элемент-функция

    man(char*); // Конструктор

    }

    //----- Функция "Изменить адрес проживания" ----------------void

    man::newadr()

    {

    int n;

    char s[80]; // Строка нового адреса

    if (address != NULL)

    delete address; // Освободить память

    printf("Введите новый адрес:");

    gets(s);

    address = new char[strlen(s)+1];// Занять новую память

    strcpy(address,s); // Заполнить поле адреса

    }

    Из данного примера видно, что именованные объекты старого класса

    можно использовать в элементах-функциях нового класса как обычные

    элементы, вызывать определенные для них элементы-функции старого класса и

    выполнять переопределенные для них операции. Заметим, что при этом

    элементы-функции нового класса не имеют доступа к приватной части

    объектов базового класса, то есть "содержимое" вложенных объектов для них

    закрыто.

    Но здесь возникает вопрос, как инициализируются и уничтожаются

    объекты старого класса при создании или уничтожении объекта нового

    класса, то есть как взаимодействуют их конструкторы и деструкторы.

    В случае, если конструктор объекта нового класса задан обычным

    образом, то перед вызовом этого конструктора будут вызваны конструкторы

    без параметров для входящих в него объектов старого класса. И наоборот,

    после вызова деструктора для объекта нового класса будут вызваны

    деструкторы вложенных объектов старого класса.

    Однако при конструировании вложенных объектов им желательно

    передавать параметры. Поэтому при описании конструктора объекта нового

    класса можно в заголовке в явном виде указать тот вид конструктора

    объекта старого класса, который требуется. Кроме того, его параметры могут

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

    class man

    {

    char name[20]; // Другие элементы класса

    dat dat1; // Дата рождения

    dat dat2; // Дата поступления на работу

    public:

    man(char *,char *,char *); // Конструкторы

    man(char *);

    }

    //----- Конструктор класса man с неявным вызовом конструкторов

    // для dat1 и dat2 без параметров

    //-----------------------------------------------------

    man::man(char *p)

    {

    }

    //----- Конструктор класса man с явным вызовом конструкторов

    // для dat1 и dat2 с параметрами

    //--------------------------------------------------------- man::man(char

    *p,char *p1, char *p2) : dat1(p1), dat2(p2)

    { ¦ ¦ ¦

    // --- Тело конструктора --- ¦ ¦ ¦

    } ¦ ¦ ¦

    Вызов конструктора для ------------------ ¦ ¦

    вложенного объекта dat1 ¦ ¦

    В качестве параметра передается ------------- ¦

    строка - второй параметр вызова ¦

    конструктора для класса man Вызов конструктора для

    вложенного объекта dat2

    void main ------ Строка конструктора man

    { ¦

    man JOHN("John","8-9-1958","15-1-1987");

    } ¦ L------ Строка передается

    Строка передается конструктору объекта

    конструктору объекта dat2 в объекте man

    dat1 в объекте man

    6.2 Производные классы

    ---------------------

    Другой случай вложенности классов основывается на понимании

    класса как совокупности данных и операций над ними. При этом

    принцип вложенности рассматривается как создание нового "производного"

    класса, который включает в себя все или большую часть

    свойств старого "базового" класса, или "наследует" их: структура

    объекта старого класса включается в новый объект, а все элементы-функции

    старого класса применимы к объекту нового класса, точнее к его старой

    составляющей.

    Старый класс при этом называется базовым классом (БК), новый

    - производным классом (ПК).

    Синтаксис определения производного класса имеет вид:

    class : ,,...

    {

    определение приватной и публичной части

    производного класса

    }

    Перечислим основные свойства базового и производного классов:

    - объект базового класса определяется в производном классе как

    неименованный. Это значит, что он не может быть использован в явном виде

    как обычный именованный объект;

    - элементы данных базового класса включаются в объект производного

    класса (как правило, компилятор размещает их в начале объекта

    производного класса). Oднако приватная часть базового класса закрыта

    для прямого использования в производном классе;

    - элементы-функции базового класса "наследуются" в производном классе,

    то есть вызов функции, определенной в базовом классе, для объекта

    производного класса возможен и понимается как вызов ее для входящего в

    него объекта базового класса;

    - в производном классе можно переопределить наследуемую функцию,

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

    соответствующих действий над объектом базового класса она может

    включать явный вызов переопределяемой функции.

    Пример схемы определения производного класса

    class a

    {

    public:

    void f() {}

    void g() {}

    }

    class b : a ------------------------ базовый класс

    {

    public: void f() -------------------- "f" переопределяется

    { ...

    a::f(); -------------- явный вызов "f" для БК

    } -------------- "g" наследуется из БК

    void h() {} -------------- собственная функция в ПК

    }

    void main()

    {

    a A1;

    b B1;

    B1.f(); --------------- вызов переопределенной b::f()

    B1.g(); --------------- вызов наследуемой a::f()

    }

    Понятие "наследования" предполагает что при вызове в производном

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

    преобразование ссылки this на объект производного класса в

    ссылку на входящий в него объект базового класса, учитывая размещение

    последнего в объекте производного класса.

    Взаимоотношение конструкторов и деструкторов базового и производного

    классов аналогичны выше описанным:

    - если конструктор производного класса определен обычным образом, то

    сначала вызывается конструктор базового класса без параметров, а затем

    конструктор производного класса. Деструкторы

    вызываются в обратном порядке - сначала для производного, затем

    для базового;

    - в заголовке конструктора производного класса может быть

    явно указан вызов конструктора базового класса с параметрами. Он

    может быть без имени, а может быть с именем базового класса. Если

    производный класс включает в себя объекты нескольких базовых

    классов, то в вызовы конструкторов базовых классов должны быть

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

    6.3 Права доступа в производных классах

    --------------------------------------

    Производный класс включает в себя как приватную, так и публичную

    часть базового класса. При этом важно, В какую часть производного класса,

    приватную или публичную, попадут соответствующие части базового класса. От

    этого зависит доступность элементов

    базового класса, как из элементов-функций производного класса,

    так и извне - через объекты производного класса. Здесь возможны

    следующие варианты:

    - приватная часть базового класса A всегда включается в приватную

    часть производного класса B, но при этом непосредственно

    недоступна из элементовфункций класса B. Это соответствует тому

    факту, что в классе B разрешается работать с базовым объектом

    класса A только разрешенными в классе A средствами, то есть через элементы-

    функции класса A. Исключение составляет объявление всего класса B

    дружественным в классе A;

    - по умолчанию, то есть при использовании заголовка вида

    class B : A { }

    публичная часть класса A попадает в приватную часть класса B. Это

    значит, что элементы-функции класса A доступны из элементов-функций класса

    B, но не могут быть вызваны извне, то есть при обращении к объектам класса

    B. То есть для внешнего пользователя класса B интерфейс класса A

    закрывается;

    - в противном случае, при объявлении

    class B : public A { }

    публичная часть класса A попадает в публичную часть класса B, и

    внешний пользователь при работе с объектами класса B может применить

    интерфейсы как производного, так и базового классов;

    - и наконец, в определении публичной части класса B можно явно

    указать элементы-функции (а также данные) публичной части базового класса

    A, которые попадают в публичную часть класса B, то есть выполнить

    предыдущее действие селективно по отношению к отдельным элементам (при этом

    указывается только имя элемента):

    class B : A {

    ...

    public:

    ...

    public A::fun;

    ...

    }

    Перечисленные варианты изображены на схеме:

    class A class B

    -----------¬ ----------------¬

    ¦ privat ======================> privat A ¦

    +----------+ ¦ (недоступен B)¦

    ¦ public ¦ class B:A +---------------+

    ¦ ======================> privat B ¦

    ¦ ¦ ¦ (доступен B) ¦

    ¦ ¦ class B : public A ¦===============¦

    ¦ ======================> public B ¦

    ¦ ¦ class B : A { ... ¦ ¦

    ¦ ¦ public A::newadr; ¦ производного класса

    L----------- L---------------

    Из рассмотренных вариантов видно, что приватная часть базового класса

    недоступна в любом производном классе, что естественно следует из свойств

    закрытости определения класса. Однако по

    аналогии с дружественностью базовый класс может разрешить доступ

    к своим элементам личной части в производных классах. Это делается при

    помощи объявления защищенных (protected) элементов.

    Элемент с меткой protected в базовом классе входит в приватную часть

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

    части производного класса. Если же базовый класс включается в

    производный как public, то защищенный элемент становится защищенным и в

    производном классе, то есть может использоваться в последующих производных

    классах. Сказанное поясним примером и схемой:

    class A

    {

    int a1; // Обычный приватный элемент

    protected: int a2; // Защищенный приватный элемент

    public:

    }

    class B : A // a1,a2 в приватной части B

    {

    void x();

    }

    void B::x()

    {

    a1 = 5; // Ошибка: a1 недоступен в B

    a2 = 3; // a2 доступен в приватной части B

    }

    class B : public A // a2 доступен и защищен в приватной

    { // части B, неявно имеет место

    // protected: int a2;

    }

    class A class B

    -----------¬ ----------------¬

    ¦ privat ======================> privat A ¦

    +----------+ ¦ (недоступен B)¦

    ¦ protected¦ class B:A +---------------+

    ¦ ======================> privat B ¦

    ¦ ===============¬ ¦ (доступен B) ¦

    +----------+ class B: public A +---------------+

    ¦ public ¦ L======> protected B ==========>

    ¦ ¦ ¦===============¦

    ¦ ¦ ¦ public ¦

    6.4 Ссылки на объекты базового и производного классов

    ----------------------------------------------------

    Из классического Си известно, что путем присваивания ссылкам

    различного типа одного и того же значения (адреса) можно работать с общей

    памятью как с различными структурами данных. При этом преобразование типа

    и присваивание не меняют значения ссылки, то есть адреса памяти.

    Применительно к базовому и производному классу можно сказать, что,

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

    базового класса, мы получаем доступ к вложенному объекту базового класса.

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

    учитывать размещение объекта базового класса в производном, что он и

    делает. В результате при таком преобразовании (присваивании) значение

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

    что такой переход от объекта производного класса к базовому часто

    встречается и корректируется транслятором, это преобразование типа ссылки в

    Си++ может бытьл выполнено неявно (остальные преобразования

    типов ссылок должны быть явнями)

    Побочный эффект такого преобразования состоит в том, что

    транслятор "забывает" об объекте производного класса и вместо

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

    class A

    {

    public: void f1();

    };

    class B : A

    {

    public: void f1(); // Переопределена в классe B

    void f2(); //

    };

    A *pa;

    B *pb;

    B x;

    pa = &x; // Неявное преобразование ссылки

    // на объект класса B в ссылку

    // на объект класса A

    pa->f1(); // Вызов функции из вложенного

    // объекта базового класса A::f1(),

    // хотя она переопределена

    Обратное преобразование от ссылки на базовый класс к ссылке

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

    такого преобразования зависит от программы:

    pb = (B*) pa; // Обратное преобразование - явное

    pb ->f2(); // Корректно, если под "pa" был

    // объект класса "B"

    6.5 Принцип объектно-ориентированного программирования

    ------------------------------------------------------

    Понятие производного класса является основой объектноориенированного

    подхода к программированию, которое можно определить

    как программирование "от класса к классу". Традиционное программирование

    "от функции к функции" предполагает, что вновь разрабатываемые структуры

    данных включают в себя определенные ранее, а

    новые функции включают вызовы ранее определенных.

    При разработке объектно-ориентированной программы программист

    создает производные классы, которые автоматически наследуют

    все свойства базовых, а затем переопределяет некоторые их функции

    и добавляет новые. В принципе ничто не препятствует на любом

    уровне разработки перейти к традиционному программированию и создавать

    Страницы: 1, 2, 3, 4, 5


    Приглашения

    09.12.2013 - 16.12.2013

    Международный конкурс хореографического искусства в рамках Международного фестиваля искусств «РОЖДЕСТВЕНСКАЯ АНДОРРА»

    09.12.2013 - 16.12.2013

    Международный конкурс хорового искусства в АНДОРРЕ «РОЖДЕСТВЕНСКАЯ АНДОРРА»




    Copyright © 2012 г.
    При использовании материалов - ссылка на сайт обязательна.