object oriented design

Published on June 2017 | Categories: Documents | Downloads: 90 | Comments: 0 | Views: 333
of 4
Download PDF   Embed   Report

Comments

Content

Object Model: Abstraction, Modularity-objects provide a more expressive and fine-grained structuring capability than decomposition by processing activity. Encapsulation: public, private interfaces. ============================= Composition.() (Inheritance-isa)(Aggregation: weak composition).Incorporating an object inside another by making the contained object a private or protected data member of the containing class creates a “part-of” relationship===================== Encapsulation Requires that functions, modules and classes: Have clearly defined external interfaces, Hide implementation details. ============================== Polymorphism: allow an interface pointer to bind to an instance of any class that implements the interface without any Direct knowledge of the derived type. ============================== code for an object factory that returns a copy of a prototype instance of some unspecified type. class PrototypeFactory{public: T* Create() { return new T(*_pPrototype); } void Register(T* pPrototype) { _pPrototype = pPrototype; }private: T* _pPrototype;};class TheObject {public: TheObject(const std::string& str) : _str(str) {} void say() { std::cout << "\n " << _str; }private: std::string _str;};int main(){ TheObject to("Hello CSE687"); PrototypeFactory<TheObject> protoFact; protoFact.Register(&to); TheObject* pTO = protoFact.Create(); pTO->say(); delete pTO;} ============================== OOD objectives:Develop High Quality Software,Reuse software components ,Manage change, Deal with complexity,Support SW design in application domain.S/w qual: Correctness,Robustness,Extendibility,Reu sability,Compatibility Performance ============================= polymorphism through pointers class base { public: base(void); base(const base &); virtual ~base(void); base& operator= (const base& b); virtual base& fun1(base& b); protected: int data; }; base::base(void){ cout << " base void constructor called\n"; } base::base(const base &b) : data(b.data) { cout << " base copy constructor called\n"; }base::~base(void) { cout << " base destructor called\n"; } base& base::operator= (const base& b) { if(this == &b) return *this; data = b.data; cout << " base operator = called\n"; return *this;}//< pass by reference > base& base::fun1(base &b) { cout << " base::fun1(base &b) called\n"; return b; class derived : public base { public:derived(void); derived(const derived &); ~derived(void); derived& operator= (const derived& b); base& fun1(base &b); derived& fun2(derived &d); private:int moredata;}; derived::derived(void){ cout << " derived void constructor called\n";} derived::derived(const derived &d) : base(d), moredata(d.moredata) { cout << " derived copy constructor called\n";}derived::~derived(void) { cout << " derived destructor called\n";} derived& derived::operator= (const derived& d) { if(this == &d) return *this; cout << " derived operator = called\n"; ((base&) *this) = d;moredata = d.moredata;return *this;}base& derived::fun1(base &b) { cout << " derived::fun1(base &b) called\n"; return b;}derived& derived::fun2(derived &d) { cout << " derived::fun2(derived &d) called\n"; return d;} void main() { message("1st"); base b1; base *bpbo=&b1; base &brbo=b1; message("2nd"); base b2; message("3rd"); bpbo->fun1(b2); message("4th"); brbo.fun1(b2); // won't compile bpbo->fun2(b1); // unknown to base brbo.fun2(b1); // polymorphic calls, e.g., derived redefined functions // called through base class pointers and refs message("5th"); derived

d1; base *bpdo=&d1; base &brdo=d1; message("6th"); bpdo>fun1(b2); message("7th"); brdo.fun1(b2);} Dark Corners 1. Compiler generated functions 2. Constructor initialization 3. Overriding errors. 4. Overloading out of scope.5. Using default parameters with virtual functions 6. Virtual destructors 7. Multiple Inheritance =================================== Composition: class composed { public: composed(void); composed(const composed& b); composed(int x); virtual ~composed(void); composed& operator= (const composed& b); friend ostream& operator<<(ostream& ostrm, const composed& b); private: int data;}; class composer { public: composer(void); composer(const composer &a); composer(int x1, int x2); virtual ~composer(void); composer& operator=(const composer&a); friend ostream& operator<<(ostream& ostrm, const composer& a); private: composed in1; composed in2;}; composed::composed(void) { cout << " composed void constructor called\n";}composed::composed(const composed& b) : data(b.data) { cout << " composed copy constructor called\n";}composed::composed(int x) : data(x) { cout << " composed(int) constructor called\n"; cout << " set data = " << data << "\n";} composed::~composed(void) { cout << " composed destructor called\n";} composed& composed::operator= (const composed& b) { if(this==&b) return *this; cout << " composed operator= called\n"; data = b.data; return *this;} ostream& operator<<(ostream& ostrm, const composed& b) { ostrm << b.data; return ostrm;} composer::composer(void) { cout << " composer void constructor called\n";} composer::composer(const composer &a) : in1(a.in1), in2(a.in2) { cout << " composer copy constructor called\n";} composer::composer(int size1, int size2) : in1(size1), in2(size2) { cout << " composer(int,int) constructor called\n"; cout << " set in1 = " << in1 << endl; cout << " set in2 = " << in2 << endl;} composer::~composer(void) { cout << " composer destructor called\n";} composer& composer::operator=(const composer &a) { if(this==&a) return *this; cout << " composer operator= called\n"; in1 = a.in1; in2 = a.in2; return *this;} void message(char *s) { cout << endl << s << " executable statement of main\n";} void main(){ message("1st"); composed inner1; message("2nd"); composed inner2 = inner1; message("3rd"); inner1 = inner2; message("4th"); composer outer1; message("5th"); composer outer2(6,4); message("6th"); composer outer3 = outer1; message("7th"); outer3 = outer2; message("no more");} =================================== Syntax equivalence class X { public: X(); // void ctor X(const X &x); // copy ctor ~X(); // dtor X& operator=(const X &x); void speak(const std::string& s); private: static int count; int myCount; }; int X::count = 0 X::X() : myCount(++count) { cout << " void ctor of object #" << myCount << "\n"; }X::X(const X &x) : myCount(++count) { cout << " copy ctor of object #" << myCount << "\n"; } X::~X() { cout << " dtor of object #" << myCount << "\n"; } X& X::operator=(const X &x) {

if(this==&x) return *this; cout << " assignment operator\n"; return *this;} void X::speak(const std::string& msg) { cout << " " << msg.c_str() << " object #" << myCount << " speaking" << endl;} void main() {//----< 6 different ways of calling void constructor >--------X x1; x1.speak("x1"); X().speak("anonymous"); // creating anonomous temporary with void ctor // X x2(); // interpreted as a function declaration // x2.speak(); X x3[2]; // void construction calls X() twice x3[0].speak("x3[0]"); x3[1].speak("x3[1]"); X* ptr = new X; // void construction calls X(); ptr->speak("on heap"); delete ptr; ptr = new X(); ptr->speak("on heap again"); delete ptr; ptr = new X[2];// void construction calls X() twice ptr->speak("X[0] on heap"); (ptr+1)->speak("X[1] on heap"); delete [] ptr; // destructor called on ptr[0] and ptr[1]; //----< 4 different ways of calling copy constructor >--------X x4 = x1; // copy construction calls X(const X &x); x4.speak("x4"); X x5(x1);x5.speak("x5, copy of x1"); X x6[2] = {x1,x4}; // " " " " twice x6[0].speak("x6[0], copy of x1"); x6[1].speak("x6[1], copy of x4"); ptr = new X(x1); // " " " " ptr->speak("copy of x1 on heap"); delete ptr; // destructor calls ~X() // ptr = new X(x1)[2]; // can't copy into heap array this way // ptr = new X[2] = {x1,x2}; // this doesn't work either //----< equivalent ways of calling an operator >--------------x5 = x1; // assignment calls X& operator(const X &x); x5.operator=(x1); // " " " "} ============================ Filemgr.cpp void FileMgr::search(const std::string& path,bool k) //searching files {for (auto patt : patterns_){find(path_, patt);} for (auto patt : patterns_){if (k==true) recursive(path_, patt);}} void FileMgr::find(const std::string& path,std::string patt) //finding files with specific pattern from path{ std::vector<std::string> files = FileSystem::Directory::getFiles(path, patt); for (auto f : files){std::string k;std::string l;std::string kl; k = FileSystem::Path::fileSpec(path, f); l = ileSystem::Path::getFullFileSpec(k); kl = ileSystem::Path::getPath(l);store_. save(kl);store_.save(f, kl);}} // recursive search of directories---------void FileMgr::recursive(const std::string& path,std::string s) {std::vector<std::string> dirs = FileSystem::Directory::getDirectories(p ath); // remove "." and ".." from dirs auto iter = std::find(std::begin(dirs), std::end(dirs), "."); if (iter != std::end(dirs)) {dirs.erase(iter);}iter = std::find(std::begin(dirs), std::end(dirs), "..");if (iter != std::end(dirs)){dirs.erase(iter);}for (auto d : dirs){std::string lk = path_ + "\\" + d;std::string p;std::string q;p = FileSystem::Path::fileSpec(path, d); q = ileSystem::Path::getFullFileSpec(p); std::vector<std::string> files = FileSystem::Directory::getFiles(q, s); for (auto f : files){std::string k;std::string l;std::string pq; k = FileSystem::Path::fileSpec(p, f);l = FileSystem::Path::getFullFileSpec(k); pq = FileSystem::Path::getPath(l);store_.save (pq);store_.save(f, pq); }recursive(lk, s);}} DataStore class DataStore {public: using Path = std::string; using Paths = std::set<Path>; using PathIters = Paths::iterator; using ListOfIters = std::list<PathIters>;

using FoundFile = std::string; using FoundFiles = std::set<FoundFile>; using PathIterations = oundFiles::iterator; using File = std::string; using Store = std::map<File, ListOfIters>; using iterator = Store::iterator; void save(const std::string& filespec) //saves path to the set container{ paths.insert(filespec);} void save(const std::string& filename, const std::string& path) //saves File anme and path to the map container {PathIters it;iterator f;std::string fn = filename;f = store.find(fn); if (f == store.end()) // if key in map is not found{store[filename].push_back(paths.in sert(path).first);}else{ListOfIters temp = f->second;temp.push_back(paths.insert (path).first);store[filename] = temp;}} void openSearch(iterator it, std::string text, FoundFiles& sf){ListOfIters tempe = it->second; for (ListOfIters::iterator ite = tempe.begin(); ite != tempe.end(); ite++) {std::string filename = **ite + it>first;std::ifstream fileinput;int offset; std::string line;std::string search = text; fileinput.open(filename); if (fileinput.is_open()){ while (!fileinput.eof()){ getline(fileinput, line); if ((offset = line.find(search, 0)) != std::string::npos){sf.insert(filename);}} fileinput.close();}else std::cout << "\n one file named " << filename << "was unable to open \n \n" << std::endl;}} Project 2 Package

CL

Ex

XP

XD

FR

XE

XO

XW

D

Project 1 package

CL

Ex

FMg

Cat

FSys

Fsch

Parameter list – local coupling;Returned items – local coupling:Returned items – local coupling:Static local data – temporal coupling:The strongest encapsulation is with only passby-value or constant reference in and out.However, the indirection allowed by non-constant references is just too powerful. We can’t live without it.We can, and should, live without global data and we should minimize the use of static local data. ->All public functions (member or global) should be have few arguments, provide conceptually simple operations. –>Don’t return pointer and references from functions,use non-const or pass by value.->write saperate fns.->Data should almost never be made public.Return pointers or references to private data only to give access to an object: char& str::operator[](int n); O.K. Composition best encapsulation, Inheritance gives derived classes access to the protected data members of the base class. Including header is encapsulation problem.

============================== Object Model: Abstraction::Application analysis: class or object model extracts the essential features of a real class or object. Software design: public interface supports simple logical model. Implementation complexity hidden from client view. Modularity: Application analysis: objects provide a more expressive and fine-grained structuring capability than decomposition by processing activity alone. Software design: objects are information clusters which can be declared as often and wherever needed. Encapsulation: Hierarchy::Form aggregations by class compositions, e.g., one class uses objects of another as data elements. Supports “partof” semantic relationship between contained and containing objects. Define subclasses of objects through inheritance from base class. Supports an “is-a” semantic relationship between derived classes and base class Three Tier Hierarchy: Inheritance has two main functions: 1) to support substitution of any one of a set of derived class instances, depending on the application context, and 2) to provide in one place code and resources that are shared across all derived instances. Any base class guarantees that code which uses a pointer or reference to the base will compile and operate with a pointer or reference to any class that publically derives from the base. It is important that you design the hierarchy so clients don't need to know the implementation details that distinguish each subtype. This substitutability is the most powerful aspect of inheritance. Design Principles:LSP supports loose couplingDon’t need to bind to concrete names. OCP demands flexibility and extendability Don’t modify, do extend. DIP avoids rigid coupling. Dependon abstraction not implementation ISP supports cohesion Factor to avoid bloated interfaces with inadvertant coupling of clients Design Strategies:Top down design: oriented decomposition, Uses successive refinement to define lower layers. Bottoms up design:Focus on encapsulating an abstraction,Provides a language for higher layers to use. Object oriented design:Partitions program activities into object interactions,Defines objects as members of families using inheritance and composition. OOD: Structuring design with classes and class relationships -Develop application-side objects:Executive, WorkingSet (inputs), Analysis, Display-Supports reasoning about application Requirements--Principles of operation,Develop solution-side objects: -Socket, SocketListener, BlockHandler OOD Strategies: Encapsulate processing in one or more classes,Extend existing classes using inheritance, Loosely couple client code to server classes. ===================================================== LSP:Functions

DS

D

Project 2 class diagram

CL

Ex

XP

XD

FR

AXL

TEX

com

XO

tag

XW

D

pro

xdec default parameters in both base and

objf

Command line,exec,xml parser,xml operations,xml writer,display,file reader,abstract xml element,text element,comments,tagged elem,proc instruction,xml declaration Project 1 class diagram

CL

Ex

FMg

Cat

that use pointers or references statically typed to some base class must be able to use objects of classes derived from the base through those pointers or references without any knowledge specialized to the derived classes.We have seen how powerful this principle is in helping us design loosely coupled systems. The base class provides a protocol for clients to use regardless of what derived class is receiving the client’s messages. Liskov Substitution breaks: if we, Override in the derived class non-virtual functions of

D Fsch

FSys

derived classes with different values for the default. Pr#2:without knowing the implementation of tagged element, proc element or document element we are accessing the functions of these classes using base class share pointer without violating any of the substituion principles using sPtr = std::shared_ptr < AbstractXmlElement > ; sPtr pDocElement_; std::shared_ptr < AbstractXmlElement > sp= makeTaggedElement(str); std::shared_ptr < AbstractXmlElement > sp3 = makeTaggedElement("SSP"); sp->addChild(makeTextElement("SaiSandesh-Pavan")); std::shared_ptr < AbstractXmlElement > sp1 = makeXmlDeclarElement(); sp1->addAttrib("Hello", "SSP Creations");

OCP:Software entities (classes, packages,

DS Encapsulation: Encapsulation is the process of implementing a class or function so that its implementation is not accessible to clients of the class. It also means that the design should not require users to know the design details of the class or function. Encapsulation prevents breakage of client design when the encapsulated entity’s implementation changes.We ensure class encapsulation by making all member data private or protected. We also need to make functions that require design knowledge to use correctly to be private or protected.Returning pointers and using non-constant reference arguments in class methods weakens encapsulation as does the use of protected data. We occasionally decide to design our classes this way for convenience, but C++11 makes it much easier to avoid at least the use of non-constant references by returning tuples instead of using side-affects to alter the state of more than one external object. Functions have four ways to interact with the external world:

functions) should be open for extension, but closed for modification.Open:A component is open if it is available for extension: add data members and operations through inheritance.Create a new policy template argument for a class that accepts policies.Closed:A component is closed if it is available for use by other components but may not, itself, be changed, e.g., by putting it under configuration management, allowing read only access.Abstract interfaces directly support the Open/Closed Principle. They must be

extended, but are closed to modification. Since they have no implementation they have no latent errors to fix and no performance issues. Pr2#, we have an abstract class called abstract xml element, whenever we find a new XML property, we can design a class inheriting abstract xml element classes without modifying the existing interface which is abstract class. Initially we did not have docElement and declaration element, since we have a interface which is open for extension we are able configure these new classes by deriving from the base class which is abstract xml element instead of modifiying xml principle itself. class AbstractXmlElement{} class DocElement : public AbstractXmlElement{}//derived frm interface DIP:Dependency inversion: High level components should not depend upon low level components. Instead, both should depend on abstractions.Abstractions should not depend upon details. Details should depend upon the abstractions. Pr2#, consider that the client is XML document, it depends on the abstract xml element for implementation details and makeElement() function for creating new objects. The XML element classes such as DocElemenet,tagged element etc uses the interface declaration of abstract xml element for their implementation. In this project, the client XMLDocument is not depending on implementation details of XMLElements, It interacts only with interface(Abstract XML element) created by XMLElement and makefactory (object factor) creates instances of required object. so now if we change implementation of XML element, it is not required to recompile Intreface Abstract XML elemnt and client code insted we will recomplie factory and implementation of XML element. provides object of interface to XMLDocument. class AbstractXmlElement{virtual std::string value() = 0;} class CommentElement: public AbstractXmlElement{std::string value() { return std::string(""); }}//derived frm interface std::shared_ptr<AbstractXmlElement> XmlProcessing::makeCommentElement(c onst std::string& text){ std::shared_ptr<AbstractXmlElement> ptr(new CommentElement(text)); return ptr;} here we removed dependency of XML document on xml element, instead it is depending on abstract base class interface abstract XML element. ISP:Interface segregation: Clients should not be forced to depend upon interfaces they do not use.this applies to clients of the public interface of a class.it also applies to derived classes. The intent of this principle is that we push interfaces down the decomposition hierarchy to the clients that really need them.-fat interfaces lead to inadvertent couplings between clients that ought to be isolated -fat interfaces can be segregated, through multiple inheritance, into abstract base classes that break unwanted coupling between components.-clients simply mixin the appropriate interfaces for their activities. Pr2#, Consider CommentElement and TextElement derived clases, which don't have any child or attributes, keeping under abstract xml element might not make perfect sense.we can create split the abstract syntax tree into a hierarchy of three interface,the main interface provides the shared pointer, another interface provides addchildren and addabributes which are essential for TaggedElement, DocElement. the final interface is for Comment and Text Element which only provides value() and toString(). ============================= Polymorphism: Polymorphism describes an Object Oriented Language’s ability to allow an interface. pointer to bind to an instance of any class that implements the interface without any direct knowledge of the derived type. The function called through the interface. pointer is determined by the class of the bound instance. This substitution capability is a very important mechanism for writing extendable code.Polymorphism places the responsibility for choosing the implementation to call with the object, not with the caller.

Here is a list of the things that break polymorphism: g -virtual member

parameters in virtual functions that differ between base and deriv default constructors at all levels of the inheritance hierarchy pr2#In project 2, we have a abstract class abstractxmlElement which acts as protocol class for all the XMLElement classes where in we override the virtual and pure virtual functions of protocol classes by polymorphism.By using shared pointer, we are accessing the overriden functions of derivedclasses, wherein we need to assign the instance of corresponding derived class to the shared pointer. using sPtr = std::shared_ptr <AbstractXmlElement>; sPtr pDocElement_; std::shared_ptr < AbstractXmlElement > sp= makeTaggedElement(str); polymoriphism/LSV Breakage: Hiding1:Don't attempt to overload functions in a different scope. class base {public: virtual ~base() {} void process(int x); void process(double d); virtual base& id();}; class derived1 : public base{public: void process(); derived1& id(); class derived2 : public base{public: derived2& id(); Hiding2: Don't overload virtual functions class base{public: virtual ~base() {} virtual void process(int x); virtual void process(double d); virtual base& id();}; class derived : public base{public: virtual void process(int i); // hides base process functions derived& id();}; vector of polys:int main(){vector<Blob*> Blobs; Blobs.push_back(new Blob("Charley")); // push_back will copy base pointers which act polymorphically. // No more slicing! Blobs.push_back(new verboseBlob("joe","ajith")); Blobs.push_back(new Blob("Frank")); sort(Blobs.begin(),Blobs.end(),lessForBlobs); vector<Blob*>::iterator it; for(it=Blobs.begin(); it!=Blobs.end(); ++it) delete *it; cout << "\n Polymorphic operation with container of pointers" << "\n but requires client to participate in memory management" << "\n\n"; } ===================================================== The C++ compilation model consists of several phases: Preprocessing replaces macros with their definitions, #include directives with the included header text, and includes or excludes source text based on #ifdef and #ifndef directives. Compilation operates on one compilation unit, e.g., a preprocessed cpp implementation file, at a time, generating obj files for each. Linking binds the obj files and any specified libraries into an executable exe file. Loading binds executable with any specified dynamic link libraries to assemble the final image in memory. The C++ compilation model encourages us to define separate packages for each program activity which are then built into an executable whole. We manage the compilation sequence with preprocessor directives and can build the project in parts for incremental testing. In Project #2 we define several packages each of which focuses on a single activity like xml document, parsing, xml element, and xml writer. Each package that depends on the services of another package must include the header file of the used package, e.g., #include “service.h”. For any standard libraries that are used by the package there must be a directive: #include <libfile>. For example XML Document we include xml element, xml parser.If you have elected to build some of the program’s services as Dynamic Link Libraries, your project must contain the Lib file that describes the DLL exports. [OHF+CHF(current.h)+.cpp]->Preprocessor->[Intermediate source code file]->compiler->[.obj file] -[.obj+other .obj+.lib]>Linker->[current.exe][.exe+.dll] ->loader->[running process]

Computational model: I/O Model:commandline,cin,stdin,ifstream,cout,stdout, ofstream. Program Model: Memory Model: (cerr,stderr,clog,stdlog)

Memory model: C++ recognizes three forms of memory: static, stack, and heap. Static Memory: Objects are created in static memory by preceding their declarations with the keyword “static”. Static objects have the life-time of the program. A static object’s constructor when static memory is initialized at the beginning of the program. Their destructors are Stack Memory: Objects are created in stack memory by declaring them as function parameters or declaring them locally in a function. Stack-based objects have a lifetime defined by the thread of execution residing within the scope in which the object is declared. Their constructors are called at the point of declaration and their destructors are called when the thread of execution Heap Memory: Objects are created on the heap by declaring them with the “new” keyword and destroying them with “delete”. Heap-based objects live from execution of the statement using “new” to the statement using “delete”. The new statement causes the allocated object’s constructor to be called and delete invokes the object’s destructor. static->(public global functions and data,private global functions and data,local static data) stack->( main stack frame,function called by main stack frame, more stack frames,current function stack frame) heap->( allocated heap memory, free heap memory) In Project 2, we are using count and tabsize as static members of Abstract XML elements which are used while displaying and writing values to file which have global access with life time of application Stack memory in several places in different functions like whenever we want to process the input string and construct abstract syntax tree.Heap Memory is used in makeElement while creating derived objects of Abstract syntax tree.In Project 1, we are using static functions from Path, Directory and File classes to get the file system information Stack memory is used in several places for processing of command line, Data Store object is build completely in stack memory passing its reference to different functions.

TEMPLATES:Templates are patterns used to generate code, instances of which, differ only in the symbolic use of a type name. Templates allow us to write one function for an unspecified type, and let the compiler fill in the details for specific type instances. A function template is a declaration for a function which uses an unspecified type T as a formal parameter, return value, or local variable. Template-based classes are classes which depend on an unspecified type as a:Formal parameter or return value of a member function.-Local variable for a member function.-Composed member of the class.Template class Instantiation stack<string> myStack; Instantiation happens at application compile time, when the compiler sees the concrete type associated with the template parameter. No code can be generated before that time, as the size of T instances is not known.-The consequence of this is that you must put all template function and class method bodies in the header file, included with application code, so the compiler sees the definition at the time the parameter is associated with a concrete type. Thus, we have a general rule: Header files contain only: Declarations, Template declarations and parameterized “definitions”, Inline function definitions. Specialization: A template specialization is the narrowing of the number of types a template accepts as arguments, possibly to one. Containers: Containers are classes which implement data structures containing objects of other classes. Often the logic necessary to manage a container is independent of its contents type, using the type only symbolically. These containers may be implemented with templates to yield a generic container. If an operation of the generic type is needed by the container, say assignment or comparison, then the type used to instantiate the container must provide it. Otherwise compilation will fail. Example: if we expect to support binary search on a generic array of objects: array<T> myArray, then the type T will need to support assignment and comparison so we can sort the array. Traits: Traits allow a template parameterized class to be used in

a function that is not aware of the parameter types.The function simply uses the “standard” name for the type provided by the class’s traits. Traits types are introduced by typedefs: typedef key key_type; template <typename T, int Size> class Array { public: typedef T value_type; typedef T* iterator; Array() : pArray(new T[Size]) {} Array(T* pT) : pArray(new T[Size]) { for(int i=0; i<Size; ++i) *(pArray + i) = *(pT + i); } T& operator[](int n) {if(n<0 || Size<=n) throw std::exception("index out of range"); return *(pArray+n); } T operator[](int n) const { if(n<0 || Size<=n) throw std::exception("index out of range"); return *(pArray+n); } iterator begin() { return pArray; } iterator end() { return (pArray + Size); } private: Array(const Array<T,Size>&); Array<T,Size>& operator=(const Array<T,Size>&) T* pArray;}; template <typename Cont> typename Cont::value_type sum(Cont& c) { Cont::iterator iter; Cont::value_type sum_ = Cont::value_type(); for(iter = c.begin(); iter != c.end(); ++iter) sum_ += *iter; return sum_;} int main(){ int temp2[] = { 1, 2, 3, 4, 5 }; Array<int,5> arr2(temp2); display(arr2); std::cout << "\n sum = " << sum(arr2) << "\n\n";} Templates and function pointers //----< declare template class taking function pointer parameter >--template<void(*f)()> class templ1 {string str; public: void show() { f(); } }; //----< declare template class taking pointer to C string >--------template<char **s> class templ2 {public: void show() { cout << "\n " << (*s); }}; tmpl1<fun1>tl; tl.show(); Template Policies:A policy is a class designed to tailor behavior of a template class in some narrow specific way struct rowDisplayPolicy{static std::string seperator() { return ", "; }}; struct columnDisplayPolicy{static std::string seperator() { return "\n "; }}; template <typename T, int Size, typename DisplayPolicy> class Array {public: Array() : pArray(new T[Size]) {} Array(T* pT) : pArray(new T[Size]) {for(int i=0; i<Size; ++i) *(pArray + i) = *(pT + i); } ~Array() { delete [] pArray; } T& operator[](int n) {if(n<0 || Size<=n) throw std::Exception("index out of range"); return *(pArray+n); } T operator[](int n) const {if(n<0 || Size<=n) throw std::Exception("index out of range"); return *(pArray+n);} void display() const {std::cout << "\n "; for(int i=0; i<Size-1; ++i) std::cout << *(pArray+i) << DisplayPolicy::seperator(); std::cout << *(pArray+Size-1) << "\n"; } private: Array(const Array<T,Size,DisplayPolicy>&); // make public impl. Later Array<T,Size,DisplayPolicy>& operator=(const Array<T,Size,DisplayPolicy>&); // ditto T* pArray;};int main(){double temp1[] = { 0, 0.5, 1.0, 1.5, 2.0 };Array<double, 5,rowDisplayPolicy> arr1(temp1);arr1.display();} ================================================ Project 2 : Abstract Syntax Tree class AbstractXmlElement { public: virtual bool addChild(std::shared_ptr<AbstractXmlElement> pChild); virtual bool removeChild(std::shared_ptr<AbstractXmlElement> pChild); virtual bool addAttrib(const std::string& name, const std::string& value); virtual bool removeAttrib(const std::string& name); virtual std::string value() = 0; virtual std::string toString() = 0; virtual ~AbstractXmlElement(); protected: static size_t count; static size_t tabSize; };

=========================== RTTI: C++ mechanism that exposes information about an object's datatype at runtime. The dynamic_cast<> operation and typeid operator in C++ are part of RTTI. RTTI is available only for classes which are polymorphic, which means they have at least one virtual method. In practice, this is not a limitation because base classes must have avirtual destructor to allow objects of derived classes to perform proper cleanup if they are deleted from a base pointer.The function: const typeinfo typeid(arg) returns a const typeinfo object when passed an object, reference, or pointer. class foo { … }; typeid(foo).name() returns “foo” foo *ptr; typeid(ptr).name() returns “foo*”; typeid(*ptr).name() returns “foo” class derived : public base { … }; typeid(base).before(typeid(derived)) returns true Shape *sp = new circle; typeid(shape) == typeid(*sp) returns false typeid(shape).before(typeid(*sp)) returns true typeid(sp).name() returns “circle*” typeid(*sp).name() returns “circle” Dynamic casts support safe down-casting. Dynamic casts support safe down-casting

============================ ObjectFactory Abstractptoduct: class AbstractProduct{public: virtual ~AbstractProduct() {} virtual id ident()=0; virtual std::string OpA()=0; virtual size_t OpB()=0;}; struct Interface1{ virtual ~Interface1() {} virtual std::string OpC() { return ""; } }; struct Interface2{ virtual ~Interface2() {} virtual std::string OpD() { return ""; }}; factory.h class Factory{public: AbstractProduct* CreateProduct(id productID);}; concreteproduct.h: class ConcreteProductA : public AbstractProduct, public Interface1 {public: id ident(); std::string OpA(); size_t OpB(); std::string OpC(); private: char buf[256]; }; class ConcreteProductB : public AbstractProduct, public Interface2 {public: id ident(); std::string OpA(); size_t OpB(); std::string OpD(); private: char buf[1024];}; concreteproduct.cpp: id ConcreteProductA::ident(){ return 1;} std::string ConcreteProductA::OpA(){ return "ConcreteProductA";} size_t ConcreteProductA::OpB(){ return sizeof(*this);} std::string ConcreteProductA::OpC(){ return "Product1 using Interface1";} Factory.cpp AbstractProduct* Factory::CreateProduct(id productID) { switch(productID) { case 1 : return new ConcreteProductA; case 2 : return new ConcreteProductB; // can add more products here default : return 0; }} Client.cpp: int main() { Factory f; AbstractProduct* pPr; pPr = f.CreateProduct(1); if(pPr) { std::cout << "\n 1st product created is " << pPr>OpA() << ". Its size is " << pPr->OpB() << " bytes."; UseInterfaces(pPr); delete pPr; }} void UseInterfaces(AbstractProduct *pAP){ Interface1* pI1 = dynamic_cast<Interface1*>(pAP);

if(pI1) std::cout << "\n " << pI1->OpC(); else std::cout << "\n can't use Interface1"; Interface2* pI2 = dynamic_cast<Interface2*>(pAP); if(pI2) std::cout << "\n " << pI2->OpD(); else std::cout << "\n can't use Interface2";}

EXCEPTIONS: -class betterUserException : public std::exception { public: betterUserException() : std::exception("betterUserException") { } virtual const char* what() const { return exception::what(); } void saveNumber(int num) { _number = num; } int savedNumber() { return _number; } private: int _number;}; -void throwBetterUserException(betterUserException &bue) { trace t("throwBetterUserException(betterUserException &bue)"); std::cout << "\n Here in throwBetterUserException(...) I'm saving a number"; std::cout.flush(); bue.saveNumber(10); throw bue;} void throwStdException(std::exception &e) { trace t("throwStdException(exception &e)"); try { throw e; } catch(const std::exception &e) { std::cout << "\n caught " << e.what(); } catch(...) { std::cout << "\n caught non-standard exception"; }} try { int x = 0, y = 1; int z = y/x; } catch(const std::exception &e) { std::cout << "\n caught " << typeid(e).name(); } catch(...) { std::cout << "\n caught non-standard exception"; }

CALLABLE INVOCATIONS: std::string testFunction(size_t lineNumber, const std::string& msg){ std::ostringstream out; out << "\n testFunction invoked from line number " << lineNumber << " - " << msg; return out.str();} class testClass {public: using F = std::function<std::string(size_t, const std::string&)>; std::string mf1(F f, size_t line, const std::string& msg) { return f(line, msg); }; using G = std::function<std::string()>; std::string mf2(G g){ return g(); } // note: no arguments, will use capture };

class Functor {public: Functor(size_t lineNumber, const std::string& msg) : ln_(lineNumber), msg_(msg) {} std::string operator()() { return testFunction(ln_, msg_); } private: size_t ln_; std::string msg_;}; main.cpp: std::cout << testFunction(__LINE__, "direct invocation");  using Fptr = std::string(*)(size_t, const std::string&); Fptr fptr = testFunction; std::cout << fptr(__LINE__, "via function pointer");  Functor functor(__LINE__ + 1, "via functor"); std::cout << functor();  std::function<std::string(size_t, const std::string&)> f = testFunction; std::cout << f(__LINE__, "via std::function<R(A...)>");  f = [](size_t size, const std::string& msg) ->std::string { return testFunction(size, msg); }; std::cout << f(__LINE__, "via lambda");  testClass tc; std::cout << tc.mf1(f, __LINE__, "via function passed to class member function");  std::string msg = "via lamda closure passed to class member function"; std::cout << tc.mf2([&]() { return testFunction(__LINE__, msg); }); // note: no argument  mutableMsg = "third message"; std::cout << [=]()->std::string { // capture all variables in scope by value // mutableMsg += " with some more text\n"; // this is an error, mutableMsg treated as const return testFunction(lineNo, mutableMsg) + " with some more text"; }();

Lambda program: #include <algorithm> void scan(int * a, int length, std::function<void (int)> func) { for(int i=0; i<length; i++) { func(a[i]); }} int main() { int a[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; int threshold = 5; int max =0; std::sort( a, &a[10], [](int x, int y){return (x < y);}); scan(a, 10, [threshold,&max](int v) { if (v>max) {max = v;} if (v>threshold) { printf("%i ", v); } }); printf("\n"); printf("Max = %i\n",max); return 0;} Read From a file line by line string line; ifstream myfile ("example.txt"); if (myfile.is_open()) { while ( getline (myfile,line) ){ cout << line << '\n';} myfile.close();} Write to a File Line by Line: ofstream myfile ("example.txt"); if (myfile.is_open()) {myfile << "This is a line.\n";myfile << "This is another line.\n";myfile.close()} Check if s1 contains S2 if (s1.find(s2) != std::string::npos) { std::cout << "found!" << '\n'; }

Template: Templates are patterns used to generate code, instances of which, differ only in the symbolic use of a type name. Templates allow us to write one function for an unspecified type, and let the compiler fill in the details for specific type instances. A function template is a declaration for a function which uses an unspecified type T as a formal parameter, return value, or local variable. Template-based classes are classes which depend on an unspecified type as a:Formal parameter or return value of a member function.Local variable for a member function.-Composed member of the class.Template class Instantiation stack<string> myStack;

A policy is a class designed to tailor behavior of a template class in some narrow specific way: Locking policy for class that may be used in multi-threaded program: template<typename T, typename LockPolicy> class queue;allows designer to use Lock or noLock policy.Enqueuing policy for a thread class: template <typename queue> class thread; Allows designer to optionally add queue and queue operations as part of thread class’s functionality.

HashTable policy for hashing table addresses: template <typename key, typename value, typename Hash> class HashTable;Allows designer to provide hashing tailored for application long after HashTable class was designed. Traits are Types and Values that Support Generic Programming. Traits types are introduced by typedefs: typedef key key_type; Program:template <typename Cont> Cont::value_type sum(Cont &c){ Cont::value_type sum = Cont::value_type(); Cont::iterator it = c.begin(); while(it != c.end()) { sum += (it>Value()); ++it; } return sum;} ====================================

Sponsor Documents

Or use your account on DocShare.tips

Hide

Forgot your password?

Or register your new account on DocShare.tips

Hide

Lost your password? Please enter your email address. You will receive a link to create a new password.

Back to log-in

Close