Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






  • Как продвинуть сайт на первые места?
    Вы создали или только планируете создать свой сайт, но не знаете, как продвигать? Продвижение сайта – это не просто процесс, а целый комплекс мероприятий, направленных на увеличение его посещаемости и повышение его позиций в поисковых системах.
    Ускорение продвижения
    Если вам трудно попасть на первые места в поиске самостоятельно, попробуйте технологию Буст, она ускоряет продвижение в десятки раз, а первые результаты появляются уже в течение первых 7 дней. Если ни один запрос у вас не продвинется в Топ10 за месяц, то в SeoHammer за бустер вернут деньги.
    Начать продвижение сайта
  • Листинг 3.1. Программа, основанная на материалах недели 3






    1: // ************************************

    2: //

    3: // Название: Обзор недели 3

    4: //

    5: // Файл: Week3

    6: //

    7: // Описание: Программа с использованием связанного списка

    8: // на основе шаблона с обработкой исключительных ситуаций

    9: //

    10: // Классы: PART - хранит номера запчастей и потенциально другую

    11: // информацию о запчастях. Зто будет

    12: // пример класса для хранения списка.

    13: // Обратите внимание на использование

    14: // оператора < < для печати информации о запчасти

    15: // на основе его типа и времени выполнения,

    16: //

    17: // Node - действует как узел в классе List

    18: //

    19: // List - список, основанный на шаблоне, который

    20: // обеспечивает работу связанного списка

    21: //

    22: //

    23: // Автор: Jesse Liberty (jl)

    24: //

    25: // Разработан: Pentium 200 Pro. 128MB RAM MVC 5.0

    26: //

    27: // Требования: Не зависит от платформы

    28: //

    29: // История создания: 9/94 - Первый выпуск (jl)

    30: // 4/97 - Обновлено (jl)

    31: // ************************************

    32:

    33: #include < iostream.h>

    34:

    35: // классы исключений

    36: class Exception { };

    37: class OutOfMemory: public Exception{ };

    38: class NullNode: public Exception{ };

    39: class EmptyList: public Exception { };

    40: class BoundsError: public Exception { };

    41:

    42:

    43: // **************** Part **************

    44: // Абстрактный базовый класс запчастей

    45: class Part

    46: {

    47: public:

    48: Part(): its0bjectNumber(1) { }

    49: Part(int 0bjectNumber): its0bjectNumber(ObjectNumber){ }

    50: virtual ~Part(){ };

    51: int GetObjectNumber() const { return itsObjectNumber; }

    52: virtual void Display() const =0; // функция будет замещена в производном классе

    53:

    54: private:

    55: int itsObjectNumber;

    56: };

    57:

    58: // выполнение чистой виртуальной функции, необходимой

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

    60: void Part:: Display() const

    61: {

    62: cout < < " \nPart Number: " < < itsObjectNumber < < endl;

    63: }

    64:

    65: // Этот оператор < < будет вызываться для всех объектов запчастей.

    66: // Его не нужно объявлять другом, поскольку он не обращается к закрытым данным.

    67: // Он вызывает метод Display(), в результате чего реализуется полиморфизм классов.

    68: // Было бы не плохо замещать функцию оператора для разных

    69: // типов thePart, но C++ не поддерживает контравариантность

    70: ostream& operator< < (ostream& theStream, Part& thePart)

    71: {

    72: thePart.Display(); // косвенная реализация полиморфизма оператора вывода!

    73: return theStream;

    74: }

    75:

    76: // **************** Car Part ************

    77: class CarPart: public Part

    78: {

    79: public:

    80: CarPart(): itsModelYear(94){ }

    81: CarPart(int year, int partNumber);

    82: int GetModelYear() const { return itsModelYear; }

    83: virtual void Display() const;

    84: private:

    85: int itsModelYear;

    86: };

    87:

    88: CarPart:: CarPart(int year, int partNumber):

    89: itsModelYear(year),

    90: Part(partNumber)

    91: { }

    92:

    93: void CarPart:: Display() const

    94: {

    95: Part:: Display();

    96: cout < < " Model Year: " < < itsModelYear < < endl;

    97: }

    98:

    99: // **************** AirPlane Part ************

    100: class AirPlanePart: public Part

    101: {

    102: public:

    103: AirPlanePart(): itsEngineNumber(1){ };

    104: AirPlanePart(int EngineNumber, int PartNumber);

    105: virtual void Display() const;

    106: int GetEngineNumber()const { return itsEngineNumber; }

    107: private:

    108: int itsEngineNumber;

    109: };

    110:

    111: AirPlanePart:: AirPlanePart(int EngineNumber, int PartNumber):

    112: itsEngineNumber(EngineNumber),

    113: Part(PartNumber)

    114: { }

    115:

    116: void AirPlanePart:: Display() const

    117: {

    118: Part:: Display();

    119: cout < < " Engine No,: " < < itsEngineNumber < < endl;

    120: }

    121:

    122: // Обьявление класса List

    123: template < class T>

    124: class List;

    125:

    126: // **************** Node ************

    127: // Общий узел, который можно добавить к списку

    128: // **********************************

    129:

    130: template < class T>

    131: class Node

    132: {

    133: public:

    134: friend class List< T>;

    135: Node (T*);

    136: ~Node();

    137: void SetNext(Node * node) { itsNext = node; }

    138: Node * GetNext() const;

    139: T * GetObject() const;

    140: private:

    141: T* its0bject;

    142: Node * itsNext;

    143: };

    144:

    145: // Выполнение узла...

    146:

    147: template < class T>

    148: Node< T>:: Node(T* p0jbect):

    149: itsObject(pOjbect),

    150: itsNext(0)

    151: { }

    152:

    153: template < class T>

    154: Node< T>:: ~Node()

    155: {

    156: delete its0bject;

    157: itsObject = 0;

    158: delete itsNext;

    159: itsNext = 0;

    160: }

    161:

    162: // Возвращает значение NULL, если нет следующего узла

    163: template < class T>

    164: Node< T> * Node< T>:: GetNext() const

    165: {

    166: return itsNext;

    167: }

    168:

    169: template < class T>

    170: T * Node< T>:: GetObject() const

    171: {

    172: if (itsObject)

    173: return itsObject;

    174: else

    175: throw NullNode();

    176: }

    177:

    178: // **************** List ************

    179: // Общий шаблон списка

    180: // Работает с любым нумерованным объектом

    181: // **********************************

    182: template < olass T>

    183: class List

    184: {

    185: public:

    186: List();

    187: ~List();

    188:

    189: T* Find(int & position, int 0bjectNumber) const;

    190: T* GetFirst() const;

    191: void Insert(T *);

    192: T* operator[](int) const;

    193: int GetCount() const { return itsCount; }

    194: private:

    195: Node< T> * pHead;

    196: int itsCount;

    197: };

    198:

    199: // Выполнение списка...

    200: template < class T>

    201: List< T>:: List();

    202: pHead(0),

    203: itsCount(0)

    204: { }

    205:

    206: template < class T>

    207: List< T>:: ~List()

    208: {

    209: delete pHead;

    210: }

    211:

    212: template < class T>

    213: T* List< T>:: GetFirst() const

    214: {

    215: if (pHead)

    216: return pHead-> itsObject;

    217: else

    218: throw EmptyList();

    219: }

    220:

    221: template < class T>

    222: T * List< T>:: operator[](int offSet) const

    223: {

    224: Node< T> * pNode = pHead;

    225:

    226: if (! pHead)

    227: throw EmptyList();

    228:

    229: if (offSet > itsCount)

    230: throw BoundsError();

    231:

    232: for (int i=0; i< offSet; i++)

    233: pNode = pNode-> itsNext;

    234:

    235: return pNode-> itsObject;

    236: }

    237:

    238: // Находим данный обьект в списке на основе его идентификационного номера (id)

    239: template < class T>

    240: T* List< T>:: Find(int & position, int 0bjectNumber) const

    241: {

    242: Node< T> * pNode = 0;

    243: for (pNode = pHead, position = 0;

    244: pNode! =NULL;

    245: pNode = pNode-> itsNext, position++)

    246: {

    247: if (pNode-> itsObject-> GetObjectNumber() == 0bjectNumber)

    248: break;

    249: }

    250: if (pNode == NULL)

    251: return NULL;

    252: else

    253: return pNode-> itsObject;

    254: }

    255:

    256: // добавляем в список, если номер объекта уникален

    257: template < class T>

    258: void List< T>:: Insert(T* pObject)

    259: {

    260: Node< T> * pNode = new Node< T> (p0bject);

    261: Node< T> * pCurrent = pHead;

    262: Node< T> * pNext = 0;

    263:

    264: int New = p0bject-> Get0bjectNumber();

    265: int Next = 0;

    266: itsCount++;

    267:

    268: if (! pHead)

    269: {

    270: pHead = pNode;

    271: return;

    272: }

    273:

    274: // если номер текущего объекта меньше номера головного,

    275: // то этот объект становится новым головным узлом

    276: if (pHead-> itsObject-> GetObjectNumber() > New)

    277: {

    278: pNode-> itsNext = pHead;

    279: pHead = pNode;

    280: return;

    281: }

    282:

    283: for (;;)

    284: {

    285: // если нет следующего обьекта, добавляем в конец текущий объект

    286: if (! pCurrent-> itsNext)

    287: {

    288: pCurrent-> itsNext = pNode;

    289: return;

    290: }

    291:

    292: // если данный объект больше текущего, но меньше следующего,

    293: // то вставляем его между ними, в противном случае переходим к следующему объекту

    294: pNext = pCurrent-> itsNext;

    295: Next = pNext-> itsObject-> GetObjectNumber();

    296: if (Next > New)

    297: {

    298: pCurrent-> itsNext = pNode;

    299: pNode-> itsNext = pNext;

    300: return;

    301: }

    302: pCurrent = pNext;

    303: }

    304: }

    305:

    306:

    307: int main()

    308: {

    309: List< Part> theList;

    310: int choice;

    311: int ObjectNumber;

    312: int value;

    313: Part * pPart;

    314: while (1)

    315: {

    316: cout < < " (0)Quit (1)Car (2)Plane: ";

    317: cin > > choice;

    318:

    319: if (! choice)

    320: break;

    321:

    322: cout < < " New PartNumber?: ";

    323: cin > > ObjectNumber;

    324:

    325: if (choice == 1)

    326: {

    327: cout < < " Model Year?: ";

    328: cin > > value;

    329: try

    330: {

    331: pPart = new CarPart(value, ObjectNumber);

    332: }

    333: catch (OutOfMemory)

    334: {

    335: cout < < " Not enough memory; Exiting..." < < endl;

    336: return 1;

    337: }

    338: }

    339: else

    340: {

    341: cout < < " Engine Number?: ";

    342: cin > > value;

    343: try

    344: {

    345: pPart = new AirPlanePart(value, ObjectNumber);

    346: }

    347: catch (OutOfMemory)

    348: {

    349: cout < < " Not enough memory: Exiting..." < < endl;

    350: return 1;

    351: }

    352: }

    353: try

    354: {

    355: theList.Insert(pPart);

    356: }

    357: catch (NullNode)

    358: {

    359: cout < < " The list is broken, and the node is null! " < < endl;

    360: return 1;

    361: }

    362: catch (EmptyList)

    363: {

    364: cout < < " The list is empty! " < < endl;

    365: return 1;

    366: }

    367: }

    368: try

    369: {

    370: for (int i = 0; i < theList.GetCount(); i++)

    371: cout < < *(theList[i]);

    372: }

    373: catch (NullNode)

    374: {

    375: cout < < " The list is broken, and the node is null! " < < endl;

    376: return 1;

    377: }

    378: catch (EmptyList)

    379: {

    380: cout < < " The list is empty! " < < endl;

    381: return 1;

    382: }

    383: catch (BoundsError)

    384: {

    385: cout < < " Tried to read beyond the end of the list! " < < endl;

    386: return 1;

    387: }

    388: return 0;

    389: }

     

    Результат:

    (0)Quit (1)Car (2)Plane: 1

    New PartNumber?: 2837

    Model Year? 90

    (0)Quit (1)Car (2)Plane: 2

    New PartNumber?: 378

    Engine Number?: 4938

    (0)Quit (1)Car (2)Plane: 1

    New PartNumber?: 4499

    Model Year? 94

    (0)Quit (1)Car (2)Plane: 1

    New PartNumber?: 3000

    Model Year? 93

    (0)Quit (1)Car (2)Plane: 0

    Part Number: 378

    Engine No. 4938

    Part Number: 2837

    Model Year: 90

    Part Number: 3000

    Model Year: 93

    Part Number 4499

    Model Year: 94

     

    Анализ: Итоговая программа, основанная на материале за неделю 3, — это модификация программы, приведенной в обзорной главе по материалам за неделю 2. Изменения заключались в добавлении шаблона, обработке объекта ostream и исключительных ситуаций. Результаты работы обеих программ идентичны.

    В строках 36—40 объявляется ряд классов исключений. В этой программе используется несколько примитивная обработка исключительных ситуаций. Классы исключений не содержат никаких данных или методов, они служат флагами для перехвата блоками catch, которые выводят простые предупреждения, а затем выполняют выход.

    Более надежная программа могла бы передать эти исключения по ссылке, а затем извлечь контекст или другие данные из объектов исключения, чтобы попытаться исправить возникшую проблему.

    В строке 45 объявляется абстрактный класс Part, причем точно так же, как это было сделано в листинге, обобщающем материал за неделю 2. Единственное интересное изменение здесь — это использование оператора operator< < (), который не является членом класса (он объявляется в строках 70—74). Обратите внимание, что он не является ни членом класса запчастей Part, ни другом класса Part. Он просто принимает в качестве одного из своих параметров ссылку на класс Part.

    Возможно, вы бы хотели иметь замещенный оператор operator< < () для объектов классов CarPart и AirPlanePart с учетом различий в типах объектов. Но поскоДьку программа передает указатель на объект базового класса Part, а не указатель на указатель производных классов CarPart и AirPlanePart, то выбор правильной версии функции пришлось бы основывать не на типе объекта, а на типе одного из параметров функции. Это явление называется контравариантностью и не поддерживается в C++.

    Есть только два пути достижения полиморфизма в C++: использование полиморфизма функций и виртуальных функций. Полиморфизм функций здесь не будет работать, сигнатуры функций, принимающих ссылку на класс Part, одинаковы.

    Виртуальные функции также не будут здесь работать, поскольку оператор operator< < не является функцией-членом класса запчастей Part. Вы не можете сделать оператор operator< < функцией-членом класса Part, потому что в программе потребуется выполнить следующий вызов:

    cout < < thePart

    Это означает, что фактически вызов относится к объекту cout.operator< < (Part&), а объект cout не имеет версии оператора operator< <, который принимает ссылку на класс запчастей Part!

    Чтобы обойти это ограничение, в приведенной выше программе используется только один оператор operator< <, принимающий ссылку на класс Part. Затем вызывается метод Display(), который является виртуальной функцией-членом, в результате чего вызывается правильная версия этого метода.

    В строках 130—143 класс Node определяется как шаблон. Он играет ту же роль, что и класс Node в программе из обзора за неделю 2, но эта версия класса Node не связана с объектом класса Part. Это значит, что данный класс может создавать узел фактически для любого типа объекта.

    Обратите внимание: если вы попытаетесь получить объект из класса Node и окажется, что не существует никакого объекта, то такая ситуация рассматривается как исключительная и исключение генерируется в строке 175.

    В строках 182—183 определяется общий шаблон класса List. Этот класс может содержать узлы любых объектов, которые имеют уникальные идентификационные номера, кроме того, он сохраняет их отсортированными в порядке возрастания номеров. Каждая из функций списка проверяет ситуацию на исключительность и при необходимости генерирует соответствующие исключения.

    В строках 307—308 управляющая программа создает список двух типов объектов класса Part, а затем печатает значения объектов в списке, используя стандартные потоки вывода.

    Если бы в языке C++ поддерживалась контравариантность, можно было бы вызывать замещенные функции, основываясь на типе объекта указателя, на который ссылается указатель базового класса. Программа, представленная в листинге 3.2, демонстрирует суть контравариантности, но, к сожалению, ее нельзя будет скомпилировать в C++.

     

    Вопросы и ответы

    В комментарии, содержащемся в строках 65-69 говорится, что C++ не поддерживает контравариантность. Что такое контравариантность?

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

     

    Предупреждение: ВНИМАНИЕ: Этот листинг не будет скомпилирован!

     

    Листинг 3.2. Пример контравариантности

    #include < iostream.h>

    class Animal

    {

    public:

    virtual void Speak() { cout < < " Animal Speaks\n"; }

    };

    class Dog: public Animal

    {

    public:

    void Speak() { cout < < " Dog Speaks\n"; }

    };

    class Cat: public Animal

    {

    public:

    void Speak() { cout < < " Cat Speaks\n"; }

    };

    void DoIt(Cat*);

    void DoIt(Dog*);

    int main()

    {

    Animal * pA = new Dog;

    DoIt(pA);

    return 0;

    }

    void DoIt(Cat * с)

    {

    cout < < " They passed а cat! \n" < < endl;

    c-> Speak();

    }

    void DoIt(Dog * d)

    {

    cout < < " They passed a dog! \n" < < endl;

    d-> Speak();

    }

     

    Но в C++ эту проблему можно решить с помощью виртуальной функции.

     

    #include< iostream.h>

    class Animal

    {

    public:

    virtual void Speak() { cout < < " Animal Speaks\n"; }

    };

    class Dog: public Animal

    {

    public:

    void Speak() { cout < < " Dog Speaks\n"; }

    };

    class Cat: public Animal

    {

    public:

    void Speak() { cout < < " Cat Speaks\n"; }

    };

    void DoIt(Animal*);

    int main()

    {

    Animal * pA = new Dog;

    DoIt(pA);

    return 0;

    }

    void DoIt(Animal * с)

    {

    cout < < " They passed some kind of animal\n" < < endl;

    c-> Speak();

    }

     

     






    © 2023 :: MyLektsii.ru :: Мои Лекции
    Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
    Копирование текстов разрешено только с указанием индексируемой ссылки на источник.