Главная страница Случайная страница Разделы сайта АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
💸 Как сделать бизнес проще, а карман толще?
Тот, кто работает в сфере услуг, знает — без ведения записи клиентов никуда. Мало того, что нужно видеть свое раписание, но и напоминать клиентам о визитах тоже.
Проблема в том, что средняя цена по рынку за такой сервис — 800 руб/мес или почти 15 000 руб за год. И это минимальный функционал.
Нашли самый бюджетный и оптимальный вариант: сервис VisitTime.⚡️ Для новых пользователей первый месяц бесплатно. А далее 290 руб/мес, это в 3 раза дешевле аналогов. За эту цену доступен весь функционал: напоминание о визитах, чаевые, предоплаты, общение с клиентами, переносы записей и так далее. ✅ Уйма гибких настроек, которые помогут вам зарабатывать больше и забыть про чувство «что-то мне нужно было сделать». Сомневаетесь? нажмите на текст, запустите чат-бота и убедитесь во всем сами! Листинг 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(); }
|