МЕНЮ


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

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


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

    if (p !=NULL)

    { // Найден - исключение из списка

    if (pred==NULL)

    fst = next;

    else

    pred->next=next;

    }

    }

    //-------------------------------------------------------void

    list::show()

    {

    list *p;

    for (p=fst; p !=NULL; p=p->next)

    { ...вывод информации об объекте... }

    }

    //------ При создании объекта он помещается в список -----------

    list::list()

    {

    insfst();

    }

    //------ При уничтожении объекта он исключается из списка ------

    list::~list()

    {

    extract();

    }

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

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

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

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

    список созданных объектов - окон. Последовательность объектов в

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

    Тогда при выполнении операции "всплытия" окна необходимо

    изменить посложение соответствующего объекта в списке. Естественно, что

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

    исключают.

    Статическими могут быть объявлены также и элементы-функции.

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

    объектом и может быть выполнен по полному имени. Соответственно в них не

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

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

    примера

    class list

    { ...

    static void show(); // Стaтическая функция просмотра

    } // всего списка объектов

    //-------------------------------------------------------static void

    list::show()

    {

    list *p;

    for (p=fst; p !=NULL; p=p->next)

    { ...вывод информации об объекте... }

    }

    //-------------------------------------------------------void main()

    { ...

    list::show(); // Вызов функции по полному имени

    }

    Лекция 4. Переопределение операторов.

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

    Напомним, что под классом понимается определяемый программистом тип

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

    зрения "равноправия" вновь вводимого типа данных желательно иметь

    возможность расширения (переопределения) операций языка, в которых один

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

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

    компилятор формирует при трансляции такой операции. Естественно, что такая

    функция должна иметь результат (значение или неявная ссылка), если

    предполагается использование этой операции внутри другого выражения.

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

    синтаксиса языка Си, то есть обозначение операций и количество операндов

    остается прежним.

    Необходимо отметить также и тот факт, что для каждой комбинации типов

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

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

    даже если базовая операция допускает это. Например, при переопределении

    операции сложения объекта

    класса dat с целым необходимо две функции dat+int и int+dat.

    Для переопределения операции используется особая форма элемента-

    функции с заголовком такого вида:

    operator( )

    При этом имя функции состоит из ключевого слова operator и

    символа данной операции в синтаксисе языка Си.

    Список формальных параметров функции является списком операндов

    (количество, типы, способы передачи) операции.

    Результат функции (тип, способ передачи) является результатом

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

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

    Имеется два способа описания функции, соответствующей

    переопределяемой операции:

    - если функция задается как обычная элемент-функция класса,

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

    ссылка на который передается неявным параметром this;

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

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

    ссылку на объект, а сам объект, тогда соответствующая элементфункция

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

    аргументов. Естественно, что полное имя дружественной функцииоператора не

    содержит при этом имени класса.

    В качестве примера рассмотрим доопределение стандартных операций над

    датами.

    #include

    #include

    #include

    static int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

    class dat

    {

    int day,month,year;

    public:

    void next(); // Элемент-функция вычисления

    // следующего для

    dat operator++(); // Операция ++

    dat operator+(int); // Операция "дата + целое"

    // с неявным операндом через this

    friend dat operator+(dat,int) // Операции с явной передачей

    friend dat operator+(int, dat) // всех параметров по значению

    dat(); // Конструкторы

    dat(int,int,int); // (см. предыдущие примеры)

    dat(char *); //

    ~dat(); // Деструктор

    }; // (см. предыдущие примеры)

    //------ Функция вычисления следующего дня --------------------//

    Используется ссылка на текущий объект this,

    // который изменяетсмя в процессе операции

    //-------------------------------------------------------void dat::next()

    {

    day++;

    if (day > days[month])

    {

    if ((month==2) && (day==29) && (year%4==0)) return;

    day=1;

    month++;

    if (month==13)

    {

    month=1;

    year++;

    }

    }

    }

    //------ Операция инкремента даты -----------------------------//1. Форма

    элемента-фукнции с неявным операндом по ссылке this

    //2. Возвращает копию входного объекта (операнда) до увеличения

    //3. Соответствует операции dat++ (увеличение после использования)

    //4. Замечание: для унарных операций типа -- или ++ использование

    // их до или после операнда не имеет значения (вызывается одна

    // и та же функция).

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

    dat dat::operator++()

    {

    // Создается временный объект

    dat x = *this; // В него копируется значение текущего объекта

    dat::next(); // Увеличивается значение текущего объекта

    return(x); // Возвращается временный объект

    }

    //------ Операция "дата + целое" ------------------------------//1. Элемент-

    функция с неявным первым аргументом по ссылке this

    //2. Входной объект не меняется, результат возвращается копией

    // внутреннего автоматического объекта x

    //-------------------------------------------------------dat

    dat::operator+(int n)

    {

    dat x;

    x = *this; // Копирование текущего объекта в x

    while (n-- !=0) x.next(); // Вызов функции next для объекта x

    return(x); // Возврат копии объекта x

    }

    //------ Операция "дата + целое" ------------------------------//1.

    Дружественная элемент-функция с полным списком аргументов

    //2. Альтернативный вариант предыдущей функции

    //3. Первый операнд класса dat - передается по значению,

    // поэтому может модифицироваться без изменения исходного объекта

    //-------------------------------------------------------dat

    operator+(dat p,int n)

    {

    while (n-- !=0) p.next(p); // Вызов функции next для объекта p

    return(p); // Возврат копии объекта x

    }

    //------ Операция "целое + дата" -----------------------------//1.

    Дружественная элемент-функция с полным списком аргументов

    //2. Второй операнд класса dat - передается по значению,

    //поэтому может модифицироваться без изменения исходного объекта

    //-------------------------------------------------------dat

    operator+(int n, dat p)

    {

    while (n-- !=0) p.next(); // Вызов функции next для объекта p

    return(p); // Возврат копии объекта p

    }

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

    void main()

    {

    int i;

    dat a;

    dat b(17,12,1990);

    dat c(12,7);

    dat d(3);

    dat e;

    dat *p = new dat[10];

    clrscr();

    e = a++;

    d=b+15;

    for (i=0; i2) && (year%4==0)) r++; // Високосный год

    r += day; // Дней в текущем месяце

    return(r);

    }

    //------ Преобразование dat в long ---------------------------//

    Используется ссылка на текущий объект this

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

    dat::opertor long()

    {

    long r; // Текущий результат

    r = 365 * (year-1) // Дней в предыдущих полных годах

    r += year / 4; // Високосные года

    r += (int)(*this); // Дней в текущем году - предыдущая

    // операция (явное преобразование

    return(r); // dat в int

    }

    //-------- Операция вычисления разницы двух дат ---------------//

    Первый операнд по ссылке на текущий объект this

    // Второй операнд по неявной ссылке p

    //-------------------------------------------------------long

    dat::operator-(dat& p)

    {

    return((long)(*this) - (long)p); // Преобразовать оба объекта

    // к типу long и вычисл. разность

    }

    void main()

    {

    dat a("12-05-1990"); // Дата, заданная текстовой строкой

    dat b; // Текущая дата

    int c;

    long d;

    // Явное преобразование к long

    printf("С 12-05-1990 прошло %4ld дней\n",(long)b-(long)a);

    // Явное преобразование к int

    printf("В этом году прошло %3d дней\n",(int)b);

    // Неявное преобразование при присваивании

    c = b;

    d = b - a; // Операция dat-dat

    printf("С 12-05-1990 прошло %4ld дней\n",d);

    printf("В этом году прошло %3d дней\n",c);

    }

    5.2 Преобразование переменной к объекту класса

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

    Данный способ не является стандартным и требует проверки

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

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

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

    xxx()". Соответственно, при явном или неявном преобразовании к классу "zzz"

    должна вызываться переопределяемая операция "operator zzz". Логично, что

    такая операция должна быть определена в классе "zzz". Но тогда имя

    соответствующей элемента-функции будет "zzz::zzz", что соответствует

    конструктору. Таким образом, если необходимо определить явное или неявное

    преобразование от базового типа или класса "xxx" к классу "zzz",

    то в классе "zzz" необходимо определить конструктор

    class zzz

    {

    int par_zzz;

    ----------------- входной тип (класс)

    zzz(xxx p); или

    zzz(xxx& p);

    L-------------------- выходной тип (класс)

    };

    void zzz::zzz(xxx &p)

    {

    par_zzz = ... p.par_xxx ...;

    элемент объекта----- L-------элемент объекта

    выходного класса входного класса

    }

    class xxx

    {

    friend class zzz;

    int par_xxx;

    };

    со следующими свойствами:

    - объект класса "zzz", который является выходным при преобразовании

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

    this;

    - элементам выходного объекта (например, par_zzz) должны быть

    присвоены значения с явным или неявным использованием ссылки this

    this->par_zzz = ...

    (*this).par_zzz = ...

    par_zzz = ...

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

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

    соответствующий формальный параметр, который может быть как значением

    (копией объекта или переменной), так и неявной ссылкой.

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

    как аргументы при преобразовании типов;

    - для доступа из функции класса "zzz" к приватной части объекта

    класса "xxx" класс "zzz" должен быть объявлен дружественным

    в определении класса "xxx".

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

    long к типу dat - количество дней от начала летоисчисления

    преобразуется к дате. Здесь же рассмотрим другой класс

    - man, в котором одним из элементов приватной части является дата.

    static int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

    class dat

    {

    int day,month,year;

    public:

    dat(long); // Преобразование long в dat

    dat(man&); // Преобразование man в dat

    dat(); // Конструкторы

    dat(int,int,int); //

    dat(char *); //

    ~dat(); // Деструктор

    };

    class man

    {

    friend class dat; // Класс dat дружественен

    ... // классу man

    int d,m,y; // Элемент "дата" в объекте

    ... // класса man

    public:

    man(dat&); // Преобразование dat в man

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

    ~man(); // Деструктор

    };

    //------ Преобразование man в dat ----------------------------

    //Используется ссылка на текущий объект this для выходного класса,

    //формальный параметр - неявная ссылка - для входного класса

    //-------------------------------------------------------void

    dat::dat(man& p)

    {

    day = p.d;

    month = p.m;

    year = p.y;

    }

    //------ Преобразование long в dat ---------------------------

    //Используется ссылка на текущий объект this для выходного класса

    //формальный параметр типа long передается по значению

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

    void dat::dat(long p)

    {

    year = p / 365.25; // Число лет с учетом високосных

    p = p - (year-1)*365L - year/4; // Остаток дней в текущем году

    year++; // Начальный год - 0001

    for (month=1; p > 0; month++) // Вычитание дней по месяцам

    {

    p -= days[month];

    if (month == 2 && year % 4 == 0) p--;

    }

    month--; // Восстановление последнего

    p += days[month]; // месяца

    if (month == 2 && year % 4 == 0) p++;

    day = p + 1;

    }

    void main()

    {

    dat a("12-05-1990"); // Дата, заданная текстовой строкой

    dat b; // Текущая дата

    int c;

    long d;

    // Явное преобразование к long

    printf("С 12-05-1990 прошло %4ld дней\n", (long)b-(long)a);

    // Явное преобразование к int

    printf("В этом году прошло %3d дней\n", (int)b);

    c = b; // Неявное преобразование при присваивании

    d = b - a; // Операция dat-dat

    printf("С 12-05-1990 прошло %4ld дней\n",d);

    printf("В этом году прошло %3d дней\n",c);

    }

    5.3 Переопределение операций new и delete

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

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

    быть переопределены следующим образом:

    void *operator new(size_t size);

    void operator delete (void *);

    где void * - ссылка на область памяти, выделяемую под объект,

    size - размер объекта в байтах.

    Переопределение этих операций позволяет написать собственное

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

    5.4 Переопределение операций [], (), ->

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

    Переопределение () :

    -------------------class one

    {

    public:

    typeout operator()(type1,type2);

    };

    Вызов:

    type1 a; // Вызов оператора совпадает с

    type2 b; // синтаксисом вызова функции

    one obj; // с именем данного объекта

    ... obj(a,b) ... эквивалентно obj.operator()(a,b)

    Переопределение -> :

    ------------------class two

    {

    public: type Y;

    };

    class one

    {

    two operator->(); // Операция должна возвращать объект

    или two* operator->(); // или ссылку на объект класса two,

    }; // в котором определен элемент Y

    Вызов:

    one obj;

    ... obj->Y .. эквивалентно (obj.operator->()) ->Y

    Переопределение [] : используется для моделирования виртуальных

    -------------------- массивов элементов определенного типа.

    class text_page

    {

    char **page; // Массив ссылок на строки

    public:

    int operator[](char*); // Ассоциативный поиск индекса

    // по строке

    char* operator[](int); // Выделение строки по индексу

    };

    5.5 Переопределение операции копирования объектов

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

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

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


    Приглашения

    09.12.2013 - 16.12.2013

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

    09.12.2013 - 16.12.2013

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




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