NEW:
Error Handling (new; not in extend details)
Assumption Error – all unknown! Assume program receives correct input ( e.g. user, file ) Assume function receives correct input (e.g. NULL pter) Assume function returns correct output (e.g. new operator return NULL coz no memory) | |||||
Solution: Check input once receive è INPUT VALIDATION Valid – continue Invalid – exit(2) ; //terminate program return 2 to OS cerr << error mssg //like cout; print error mssg do other thing return –1 // error code to caller
| |||||
Solution group by one: #include <cassert> assert(valid condition) àif false (TRY): (CATCH)printout assertion failed: invalid condition, line 7, terminated program |
Exception
try //referee { // Statements that may throw exceptions you want to handle now go here //flags (exceptions) up if… throw -1; // throw a literal integer value throw ENUM_INVALID_INDEX; // throw an enum value throw "Can not take square root of negative number"; // throw a literal char* string throw dX; // throw a double variable that was previously defined throw MyException("Fatal Error"); // Throw an object of class MyException } catch (int) // { // Any exceptions of type int thrown within the above try block get sent here cerr << "We caught an exception of type int" << endl; } catch (double) { // Any exceptions of type double thrown within the above try block get sent here cerr << "We caught an exception of type double" << endl; } | |
Try{ // Here's all the normal code logic m_nFirstParameter = ReadParameter(fSetupIni); //throws exception on failure, jump to enclosing try m_nSecondParameter = ReadParameter(fSetupIni); m_nThirdParameter = ReadParameter(fSetupIni); catch (int) // Here's the error handling, nicely separated return ERROR_PARAMETER_MISSING; // Some other enum value indicating error | |
double MySqrt(double dX) { // If the user entered a negative number, this is an error condition if (dX < 0.0) throw "Can not take sqrt of negative number"; // throw exception of type char* if (…) throw –1 ; return sqrt(dX); } | int main() { cout << "Enter a number: "; double dX; cin >> dX; try // Look for exceptions that occur within try block { cout << "The sqrt of " << dX << " is " << MySqrt(dX) << endl; } catch (char* strException) // catch exceptions { cerr << "Error: " << strException << endl; catch(...) { cerr << "Abnormal termination" << endl; |
If throw, jump to the enclosing try, find the attached catch; Repeat jump to the next enclosing try, find the attached catch – (unwinding the stack) Catch’s Char* strException= Throw’s “Cannot take sqrt of negative number” Continue the remaining code after Catch - exception handled; unhandled exception error if not found (except use catch all handler catch(…) so that program will not terminated) |
Compare to Normal, Route from Throw to Catch and Not terminating are additional : |
Normal: Cerr airplane cannot take –1 passengers in function Sqrt, then how about other main call Sqrt? Exception: pass back to each caller for different Action (Catch) e.g. “airplane cannot take –1 passengers” the function just acts there is error (Throw) |
pass back variable which can be used |
Normal: terminating by return but I wanna continue the function! |
Exception Class
Try { int *nValue = new int(anArray[nIndex1] + anArray[nIndex2]); } Catch (int nValue) { // What are we catching here? From function new? From operator +?? Except using char* (throw “specific error for function1), we can use exception class to describe the problem | |
class ArrayException { private: std::string m_strError; ArrayException() {}; // not meant to be called public: ArrayException(std::string strError) : m_strError(strError) { } std::string GetError() { return m_strError; } } | int IntArray::operator[](const int nIndex) { if (nIndex < 0 || nIndex >= GetLength()) throw ArrayException("Invalid index"); //throw an object (variable) so below use reference return m_nData[nIndex]; } try { int nValue = anArray[5]; } catch (ArrayException &cException) { cerr << "An array exception occurred (" << cException.GetError() << ")" << endl; } //use object.method() to describe the problem instead of char* |
throw Derived(); //to map correctly, should avoid Base &cBase= Deriv obj catch (Derived &cDerived) //correct order catch (Base &cBase) |
Warning for using try catch
Try { pJohn = new Person("John", 18, E_MALE); //jumps to catch and didn’t deallocate so that in catch … catch (PersonException &cException) { CloseFile(strFilename); delete pJohn; //need to declare pJohn=NULL out of block so that we can access in catch or #include <memory> // for std::auto_ptr auto_ptr<Person> pxJohn(pJohn); // pxJohn now owns pJohn and if jumps to catch, deallocate it (no need to call delete) //use vector class if pJohn is array |
Catch { //unwinding stack – another function catch after throw ~student à throw exception again! //destructor because need to deallocate memory of field Cerr…. //so handle ~student exception? Or continue cerr <<….? Terminate immediately As a result, do not throw exception in destructor but good for constructor |
Input Validation
Char (letters+int) validation #include <cctype>
| ||||||||||||||||||
|
Int (int only) validation |
Cin.fail() to ensure it is integer type and no letters; if not, clear() and ignore() |
Link List, Queue, Stack implementation
#include <iostream> using namespace std; template <class T> class Stack; template <class T> class SNode{ T _data; SNode<T>* _next; SNode(T data, SNode<T>* next){ _data = data; _next = next; } friend class Stack<T>; }; template <class T> class Stack{ SNode<T>* _top; public: Stack(); void push(T data); T pop(); bool isEmpty()const; virtual ~Stack(); }; template <class T> Stack<T>::Stack(){ _top = (SNode<T>*)0; } template <class T> void Stack<T>::push(T data){ SNode<T>* temp = new SNode<T>(data,_top); _top = temp; } template <class T> T Stack<T>::pop(){ T val = _top->_data; SNode<T>* toDel = _top; _top = _top->_next; delete toDel; return val; } template <class T> bool Stack<T>::isEmpty()const{ return !_top; } template <class T> Stack<T>::~Stack(){ SNode<T>* toDel; while(_top){ toDel = _top; _top = _top->_next; delete toDel; } } int main(){ Stack<int> S; int i; for(i=100;i<2000;i+=10){ S.push(i); } while(!S.isEmpty()){ cout<<S.pop()<<" "; } cout<<endl<<"*******************************************"<<endl; for(i=100;i<2000;i+=10){ S.push(i); } for(i=0;i<10;i++){ cout<<S.pop()<<" "; } cout<<endl<<"*******************************************"<<endl; return 0; } |
#ifndef __TQUEUE_H__ #define __TQUEUE_H__ /* template signatures: 1- all related classes and types will have the signature 2- the name of the class right after the template will NOT have the signature 3- the constructor names will NOT have the signature 4- the destructor name will NOT have the signature */ /* Tqueue requirements: 1- Template class must be copied safely. 2- Template class must work with operator< */ template <class type> class Tqueue; template <class type> class Tqnode{ Tqnode<type>* _next; Tqnode<type>* _prev; type _data; Tqnode(type data, Tqnode<type>* prev = (Tqnode<type>*)0, Tqnode<type>* next = (Tqnode<type>*)0):_data(data){ _next = next; _prev = prev; } friend class Tqueue<type>; }; template <class type> class Tqueue{ Tqnode<type>* _head; Tqnode<type>* _curr; Tqnode<type>* _tail; public: Tqueue(){ _head = _tail = _curr = (Tqnode<type>*)0; } virtual ~Tqueue(){ goHead(); while(_curr){ _head = _curr; _curr = _curr->_next; delete _head; } } bool goNext(); bool goPrev(); bool goHead(); bool goTail(); bool isEmpty(){ return !_curr; } void append(type data){ // appends to tail Tqnode<type>* temp= new Tqnode<type>(data, _tail); if(_curr){ _tail = temp; _tail->_prev->_next = _tail; // _temp->_prev->_next = _temp; } else{ _curr = _head = _tail = temp; } } type remove(){ // removes the data from the head of the list if(_head == _tail){ type data = _head->_data; delete _head; _head = _tail = _curr = (Tqnode<type>*)0; return data; } else{ type data = _head->_data; Tqnode<type>* todel = _head; if(_head == _curr){ _curr = _curr->_next; } _head = _head->_next; _head->_prev = (Tqnode<type>*)0; delete todel; return data; } } void insertBefore(type data); // before current (prev side) void insertAfter(type data); // after current (next side) type visit(){ // returs the data of the current return _curr->_data; } type removeCurrent(); // removes curent bool sort(bool Ascending = true); // sorts the nodes void push(type data); type pop(); }; template <class type> bool Tqueue<type>::goTail(){ bool res = false; if(_curr){ // is not null _curr = _tail; res = true; } return res; } template <class type> bool Tqueue<type>::goHead(){ bool res = false; if(_curr){ // is not null _curr = _head; res = true; } return res; } template <class type> bool Tqueue<type>::goNext(){ bool res = false; if(_curr && _curr->_next){ _curr = _curr->_next; res = true; } return res; } template <class type> bool Tqueue<type>::goPrev(){ bool res = false; if(_curr != _head){ _curr = _curr->_prev; res = true; } return res; } #endif |
#ifndef __TQUEUE_H__ #define __TQUEUE_H__ template <class T> class Tqueue; template <class T> class Tqnode{ Tqnode<T>* _next; Tqnode<T>* _prev; T _data; Tqnode(T data, Tqnode<T>* prev = (Tqnode<T>*)0, Tqnode<T>* next = (Tqnode<T>*)0):_data(data){ _next = next; _prev = prev; } friend class Tqueue<T>; }; template <class T> class Tqueue{ Tqnode<T>* _head; Tqnode<T>* _curr; Tqnode<T>* _tail; public: Tqueue(); virtual ~Tqueue(); bool goNext(); bool goPrev(); bool goHead(); bool goTail(); bool isEmpty(); void append(T data);// appends to tail T remove(); // removes the data from the head of the list void insertBefore(T data); // before current (prev side) void insertAfter(T data); // after current (next side) T visit(); // returs the data of the current T removeCurrent(); // removes curent bool sort(bool Ascending = true); // sorts the nodes void push(T data); T pop(); }; template <class T> Tqueue<T>::Tqueue(){ _head = _tail = _curr = (Tqnode<T>*)0; } template <class T> Tqueue<T>::~Tqueue(){ goHead(); while(_curr){ _head = _curr; _curr = _curr->_next; delete _head; } } template <class T> T Tqueue<T>::visit(){ return _curr->_data; } template <class T> bool Tqueue<T>::sort(bool Ascending){ Tqnode<T>* tmp = _curr = _head; bool done = false; goNext(); while(tmp && tmp->_next){ if((Ascending && tmp->_data > _curr->_data) || (!Ascending && tmp->_data < _curr->_data)){ T buff = tmp->_data; tmp->_data = _curr->_data; _curr->_data = buff; } if(!goNext()){ tmp = tmp->_next; if(tmp->_next) _curr = tmp->_next; else done = true; } } return done; } template <class T> void Tqueue<T>::append(T data){ _tail = new Tqnode<T>(data, _tail); if(_curr) _tail->_prev->_next = _tail; else _curr = _head = _tail; } template <class T> T Tqueue<T>::remove(){ T data = _head->_data; if(_head == _tail){ delete _head; _head = _tail = _curr = (Tqnode<T>*)0; } else{ Tqnode<T>* todel = _head; if(!_curr->_prev)_curr = _curr->_next; _head = _head->_next; _head->_prev = (Tqnode<T>*)0; delete todel; } return data; } template <class T> void Tqueue<T>::insertBefore(T data){ if(_curr){ _curr = new Tqnode<T>(data, _curr->_prev, _curr); _curr->_next->_prev = _curr; if(_curr->_prev) _curr->_prev->_next = _curr; else _head = _curr; } else _tail = _head = _curr = new Tqnode<T>(data); } template <class T> void Tqueue<T>::insertAfter(T data){ if(_curr){ _curr = new Tqnode<T>(data, _curr, _curr->_next); _curr->_prev->_next = _curr; if(_curr->_next) _curr->_next->_prev = _curr; else _tail = _curr; } else _tail = _head = _curr = new Tqnode<T>(data); } template <class T> T Tqueue<T>::removeCurrent(){ T data = _curr->_data; if(_curr == _head){ data = remove(); } else{ Tqnode<T>* todel = _curr; if(_tail == _curr){ _curr->_prev->_next = (Tqnode<T>*)0; _curr = _tail = _curr->_prev; } else{ _curr->_prev->_next = _curr->_next; _curr->_next->_prev = _curr->_prev; _curr = _curr->_next; } delete todel; } return data; } template <class T> void Tqueue<T>::push(T data){ _head = new Tqnode<T>(data, (Tqnode<T>*)0, _head); if(_curr) _head->_next->_prev = _head; else _curr = _tail = _head; } template <class T> T Tqueue<T>::pop(){ return remove(); } template <class T> bool Tqueue<T>::isEmpty(){ return !_curr; } template <class T> bool Tqueue<T>::goTail(){ bool res = false; if(_curr){ // is not null _curr = _tail; res = true; } return res; } template <class T> bool Tqueue<T>::goHead(){ bool res = false; if(_curr){ // is not null _curr = _head; res = true; } return res; } template <class T> bool Tqueue<T>::goNext(){ bool res = false; if(_curr && _curr->_next){ _curr = _curr->_next; res = true; } return res; } template <class T> bool Tqueue<T>::goPrev(){ bool res = false; if(_curr->_prev){ _curr = _curr->_prev; res = true; } return res; } #endif |
Learn class notes with topics
Jan 12 | Namespace |
Jan 19 | Macros |
Jan 23 | Default para, function overloading |
Jan 26 | Array and pointer |
Jan 30 | Static, class, dynamic memory, ((ostream& const <<)) (Recursion base case), (Boolean while(0)) |
Feb 2 | Pointer to function (ftrp 8?), operator in c, ((virtual)) |
Feb 6 | Reference, (integer size) |
| |
Mar 8 | Bit operator |
Mar 12 | Print bits, Template |
Mar 15 | Template (stack) |
Learnc++
Chapter | Finish | Skip |
1 | 1.1-1.9 | 1.10 |
2 | 2.1-2.10 | |
3 | 3.1-3.9 | |
4 | 4.1-4.3, 4.5 | 4.4, 4.6-4.7(typedef, struct) |
5 | | 5.1-5.9(control structure) |
6 | 6.1-6.3, 6.5-6.13 | 6.4 (selection sort) |
7 | 7.1-7.8, 7.11-7.14 | 7.9-7.10 (stack, recur) |
8 | 8.1,8.10 | 8.2-8.9, 8.11-8.14 |
9 | | 9.1-9.12 |
10 | 10.1 | 10.2-10.4(terms) |
11 | 11.1-11.8 | |
12 | 12.1-12.3 | 12.4-12.5(bind), 12.6(interfaceclass) |
13 | 13.1-13.2, 13.5-13.7 | 13.3-13.4(out format, stringclass) |
14 | 14.1-14.5 | 14.6(partial template) |
15 | 15.1-15.6 | |
16 | / | / |
17 | / | / |
project
cout=console
machine code without source file during linkage
so we write console
why extern console??
See cout is object and we can use. It must be created in iostream
So we create extern console (cout) so that we can use the cout.display() to output something on screen!
//object cannot be visualized
//but this project, we draw something out, so we can visualize to difference them~!
//Console holds info, which we can imagine as a screen
//Cframe holds info, which we can imagine as a border
//Cfield holds info, which draw as a frame+data
//Cbutton holds info, which draw as a frame + holds text
//Ccheckmark holds info, which draw as a frame + holds 1/0
//Cdialog holds info, which draw as a frame + holds Cfield
*****Cbutton is assign _frame 0 so that it should be fullscreen when draw, but Cdialog add them add() and make cbutton’s _frame to the container so that it is not fullscreen (not draw border) but inside the dialog when draw
Debug for my notes mistake:
*overload type casting means: when u do type casting, it will~ provide class type casting
For Cbutton constructor, we need _data to have string, so we can put string Str to the Cfield constructor and assign it to _data
à problem is _data is void* and str is const char* not just char*
à solution is we cannot assign str to cfield constructor so that we assign it as 0 and then assign _data outside of cfield constructor, define in body
*overload definition It is simply defined as the ability of one function to perform different tasks.
ask prof:
static
Terms:
Relationship of Classes=
1. Association= Object use another Class’s Methods
2. Composition= Class inside Class
Encapsulation(classes start)=
1. hiding (cannot see) Methods logic and Instance data inside class except external appearance
2. by using separate source file- and the original module which consists of Interface (header file .h file) and Implementation (how it works .c .cpp file which is being compiled) (p.s. C also have this feature tho)
3. instance data (object field) inside the Class can only be modified by methods inside the Class
4. by using public and private modifier for Methods and Field inside Class (p.s. C dun have)
Polymorphism=
1. Language select method of the object’s class which is most appropriate
2. Identical method
3. Different method= Different part + identical method
4.
Language Difference= Concept of Java – Concept of C= Concept of Class and objects (no C but java c++)
Concept’s (where C dun have) feature=Include import, Encapsulation, Inheritance, Polymorphism
------------------------------------------------------------------------------------------------------------------------------------------------
1. if (student!=NULL) //already allocate dymamic memory to pointer student then delete student
2. student=NULL; //to ensure not deleting twice as serious error
3. student= new (nothrow) Student [n]; // new (nothrow) returns NULL if memory allocation fails; if success like above, allocate additional address will be stored in pointer (student) variable
Memory Issues- Memory Leaks, Insufficient memory
Insufficient Memory=
1. Solution= use new (nothrow)
OOP344B | 2012/04/17 | 14:00 | 16:00 | T4040 | Seneca@York |