1 / 30

Informatik I (D-ITET) Group 7, 15:00-17:00, ETZ H91 Assistant: Ercan Ucan

Informatik I (D-ITET) Group 7, 15:00-17:00, ETZ H91 Assistant: Ercan Ucan. Slides at http://people.inf.ethz.ch/eucan/inf-1 /. Exercise 10 ( 3 /12/2012 ) . Series 8. Towers of Hanoi (pseudo-code): void hanoi ( int n, int p1, int p2, int p3) { if ( n<0) return;

leoma
Download Presentation

Informatik I (D-ITET) Group 7, 15:00-17:00, ETZ H91 Assistant: Ercan Ucan

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Informatik I (D-ITET)Group 7, 15:00-17:00, ETZ H91Assistant: Ercan Ucan Slides at http://people.inf.ethz.ch/eucan/inf-1/ Exercise10(3/12/2012)

  2. Series 8 • Towers of Hanoi (pseudo-code): • void hanoi(intn, int p1, int p2, int p3) • { • if (n<0) • return; • hanoi(n-1, p1, p3, p2); • printf("Move the top disc from %d to %d.\n", p1, p2); • hanoi(n-1, p3, p2, p1); • }

  3. Object-Oriented Programming (OOP) • OOP features: • Abstraction (focus on a few concepts at a time) • Encapsulation and data hiding (the internal representation of an object is generally hidden from view outside the object’s definition) • Polymorphism (being able to use one type A in the same way as another type B, e.g. with operator overloading) • Inheritance (design new classed using attributes and functions of classes that have already been defined) • Reusability of code and modularity • The class is the most important C++ enhancement for implementing the above features. A class is a construct that is used as a template to create objects of that class. This template describes the state and behavior that the objects of the class all share. An object of a given class is called an instance of the class.

  4. Class Declaration Keyword class identifies class definition The class name becomes the name of this user-defined type Class Stock { private: char company[30]; int shares; double share_val; double total_val; void set_tot() {total_val = shares*share_val;} public: void acquire(const char * co, int n, double pr); void buy (int num, double price); void sell (int num, double price); } Class members can be either data types or functions (extension of structs) Keyword private identifies class members that can be accessed only through the public member functions (data hiding). Keyword public identifies class members that form the public interface for the class (abstraction).

  5. Object Declaration After declaring the class Stock we have specified a new type named Stock. This declaration enables us to declare now variables called objects or instances of this user-specified type. Thus we can write: Stock thomas; Stock peter; Defining two objects of the class Stock. We have already used classes in our code, e.g. when you are using the class string and then methods defined for this class, or the member functions of istream and ostream classes. string name=“Ercan”; cout << “The length of my name is” << name.length(); Or ofstreammyfile; myfile.open ("example.txt"); Class Stock { private: char company[30]; int shares; double total_val; void set_tot() {total_val = shares*share_val;} public: void buy (int num, double price); void sell (int num, double price); }

  6. Implementing Class Member Functions • So far we have declared the member functions but we haven’t specified what they do. • Member functions definitions are like regular function definitions, except that: • When defining a member function you have to use the scope-resolution operator (::) • to identify the class to which the function belongs. • Class methods can access the private components of the class. void Stock::buy(int num, double price){ if (num < 0){ std::cerr << “Number of shares purchased cannot be negative”; } else{ shares +=num; share_val = price; set_tot(); } }

  7. Implementing Class Member Functions :: resolves the identity of a class to which a method definition applies. void Stock::sell (int num, double price){ if (num < 0){ std::cerr << “Number of shares sold cannot be negative”; } else if (num > shares){ std::cerr << “You can’t sell more than you have”; } else{ shares -=num; share_val = price; set_tot(); } } You can access the private part of the class declaration. The easy way is to define the class member functions after the declaration of the class in the same file. But it’s not the best way as we will see later.

  8. Implementing Class Member Functions Are we forgetting anything? We need a function to initialize the class member variables for a given instance. We will see later on how to do it in a more proper and consistent way. void Stock::acquire (const char *co, int num, double price){ std::strncpy(company, co, 29); //Truncate co to fit company company[29] = ‘\0’; if (num < 0){ std::cerr << “Number of shares sold cannot be negative”; shares = 0; } else shares = num; share_val = price; set_tot(); }

  9. Another Example #include <iostream> usingnamespace std; classCRectangle{ private: int x, y; public: voidset_values (inta,int b); int area () {return (x*y);} }; voidCRectangle::set_values (int a, int b) { x = a; y = b; } int main () { CRectangle recta, rectb; recta.set_values (3,4); rectb.set_values (5,6); cout << "recta area: " << recta.area() << endl; cout << "rectb area: " << rectb.area() << endl; return 0; } 2 instances of class CRectangle

  10. Initialize class objects • Generally, objects need to initialize their variables or assign dynamic memory during their point of creation in order to become operative. • With structs you can write something like this: • struct thing { • char * pn; • int m; • }; • thing test = {“blabla”, 2}; // THIS IS VALID • Stock maria = {“Maria AG stocks”, 100, 10.1} // NOT VALID • So you cannot initialize class objects in the same way you do with the structs, and the reason is that the data parts have private access status, which means a program cannot access the data members directly. • In general it is best practice to initialize all objects when they are created and you do so using the special C++ member functions, called class constructors, and respectively the class destructors, to perform the opposite.

  11. Constructors • First you have to add the constructor prototype in the class declaration, which in our example will look like : Class Stock { private: char company[30]; int shares; double total_val; void set_tot() {total_val = shares*share_val;} public: Stock(const char * co, int n, double pr); void acquire(const char * co, int n, double pr); void buy (int num, double price); void sell (int num, double price); }

  12. Constructors • And then you have to specify what this special member function, which we call constructor does, for example: • You can see that this is exactly the code for the function Stock::acquire . The only difference is that now the program automatically invokes the constructor when it declares an object. void Stock::Stock (const char *, int num, double price){ std::strncpy(company, co, 29); //Truncate co to fit company company[29] = ‘\0’; if (num < 0){ std::cerr << “Number of shares sold cannot be negative”; shares = 0; } else shares = num; share_val = price; set_tot(); }

  13. Using Constructors • Since we defined a constructor we can now use it : • Stock food = Stock(“Tomato AG”, 1000, 10.34); //Explicit call • Stock food(“Tomato AG”, 1000, 10.34); //Implicit call • Stock *pstock = new Stock(“Tomato AG”, 1000, 10.34); //Dynamic memory allocation • Note the difference of a constructor and other class methods: • Since when you call a constructor you haven’t yet created an object there is no point in calling the constructor like a normal method, e.g. food.stock(…)

  14. Default Constructors - BE CAREFUL !!! • If you don’t specify a constructor in your program, then C++ automatically supplies a default constructor which doesn’t do and initialize anything, e.g. • Stock::Stock() {} • From the moment you have specified ANY constructor for a class, it is your responsibility to specify the default constructor. And you can do that in two ways: • Provide default values for all the input arguments to the existing constructor, e.g. • public: • Stock(const char * co = “Error”, int n=0, double pr=0.0); • Overload the function to create a second constructor with no arguments, e.g. • public: • Stock(const char * co, int n, double pr); • Stock(); Stock::Stock() { std::strcpy(company, “no name”); shares = 0; share_val = 0.0; total_var = 0.0; } Then you can call: Stock temp; //Implicit call Stock temp = Stock(); //Explicit call

  15. Destructors • When using a constructor to create an object the program is responsible to trace it until it expires, when a special member function, called class destructor, is called in order to clean up the mess. • You can understand that this is of extreme importance if you have dynamically allocated space and you have to deallocate it using delete() . Otherwise there is nothing to be done and you can let the program generate an implicit, do-nothing destructor. • Defining a destructor : • public: • Stock(const char * co, int n, double pr); • ~Stock(); • …. • Stock::~Stock() { • cout << “Bye bye stock”; // Just to trace when the destructor is called • //delete something if needed etc… • }

  16. Destructors • In principle, you should NOT call yourself the destructors. • The compiler takes care of this decision, when to call the destructor. So it looks when an object is no longer needed and then looks if a destructor has been specified. If not, then the default destructor is called. Otherwise the one that has been specified. • So it is your responsibility to correctly clean up the mess you have probably created in your program, but you don’t need to specify when to do it.

  17. Improving your code when working with classes • Suppose that you want to deliver an implementation of the Stock class. A recommended good practice is to follow the steps: • Place the class declarations in a header file called, for example, stock1.h • Place the class methods definitions in a cpp file called, for example, stock1.cpp (Having the same name is convenient in order to keep track of which files go together). • Place your main program that uses this class in another cpp file, for example, stockMarket.cpp

  18. Improving your code when working with classes • The header file // stock1.h – Stock class declaration #ifndef STOCK1_H_ #define STOCK1_H_ Class Stock { private: char company[30]; int shares; double share_val; double total_val; void set_tot() {total_val = shares*share_val;} public: Stock(); Stock(const char * co, int n, double pr); ~Stock(); void buy (int num, double price); void sell (int num, double price); } #endif Used to avoid multiple inclusions of header files. It means basically, process the statements between #ifndef and #endif if the name STOCK1_H_ is still undefined.

  19. Improving your code when working with classes • The implementation file // stock1.cpp – Stock class implementation #include <iostream> #include “stock1.h” Stock::Stock(){ … } Stock::Stock(const char * co, int n, int pr){ … } void Stock::buy(int num ,double price){ … } void Stock::sell(int num ,double price){ … } etc. etc.

  20. Improving your code when working with classes • The main test program // stockMarket.cpp – Stock class testing #include <iostream> #include “stock1.h” int main() { Stock stock1(“Microsoft”, 100000, 100.0); Stock stock2 = Stock(“IBM”,1,0.001); stock1.buy(100,150.0); stock2.sell(1,0.00001); return 0; }

  21. The this pointer • this is a special pointer which points to the object used to invoke a member function. • For example, suppose we have created two objects • Stock microsoft = Stock(“Microsoft”, 100000, 100.0); • Stock ibm = Stock(“IBM”,10,0.001); • Then if you call • microsoft.buy(10,150.0); • The pointer this in the body of the method will point to the object microsoft. And as you did with structs you can use -> to dereference the members of the object. Microsoft 1000000 100 10000000 IBM 10 0.001 0.01 void Stock::buy(int num, double price){ if (num < 0){ std::cerr << “blabla” } else{ shares +=num; share_val = price; cout << this->total_val <<“CHF”; set_tot(); } }

  22. Operator Overloading • Operator overloading is an example of C++ polymorphism. • Enables more natural-looking code. Think for example what you have to do in order to add two vectors. Normally you have to code something like: • for (inti = 0; i < 20; i++) • sum[i] = array1[i] + array2[i]; • But in C++ you can define a class that represents arrays and then you can overload the ‘+’ operator in a convenient way, e.g. • sum = array1 + array2; //array1 and array2 are two objects of the class Array. • To do that you have to use a special function form, called an operator function : • operatorop(arguments) • where op is the symbol for the operator you want to overload. • For example if you want to overload the ‘+’ operator you have to write: • operator+(arguments) • if you want to overload the ‘<<’ operator you have to write: • operator<<(arguments) etc

  23. Operator Overloading (Example) #include <iostream> using namespace std; class CVector { public: intx,y; CVector () {}; CVector (int,int); CVector operator+(CVector); }; CVector::CVector (int a, int b) { x = a; y = b; } CVectorCVector::operator+ (CVectorparam) { CVector temp; temp.x = x + param.x; temp.y = y + param.y; return (temp); } int main () { CVector a (3,1); CVector b (1,2); CVector c; c = a + b; cout << c.x << "," << c.y; return 0; } And the result of the main() is : 4,3

  24. Exercise 1 • You have to implement a data structure called FIFO (First-In-First-Out) Queue, which is pretty similar to the stack you implemented in series 6. • This time you are NOT allowed to use stacks, but you have to do everything with classes. • Internally, you will represent the queue as a linked list, as you did with the stack. • Basically you have to implement 2 classes: • Class QueueElement • Class StringQueue

  25. Exercise 1 – Class QueueElement • Class QueueElement : • Each object of the class should store a string and a pointer to the next element in the queue. • Since the string does not need to be changed, it should be passed as argument to the constructor of queue element. • The variables for the string and the pointer should be private and read only through public methods. • Write a header file QueueElement.h, which contains this description of the Queue class interface element. Implement the class and its methods then in QueueElement.cpp.

  26. Exercise 1 – Class QueueElement • // QueueElement.h • #include <string> • using namespace std; • #ifndef QUEUEELEMENT_H_ • #define QUEUEELEMENT_H_ • class QueueElement { • public: • QueueElement(const string aValue); // The Constructor • QueueElement* getNext(); // Get the pointer to the next element • void setNext(QueueElement* anElement); // Set the pointer to the next element • string getValue(); // Read the value for the string field • private: • string value; //This is basically the structure of the each object • QueueElement* next; • }; • #endif /* QUEUEELEMENT_H_ */

  27. Exercise 1 – Class StringQueue • Class StringQueue : • This class will manage a queue of strings. • The strings will be stored in objects of the previously implemented class QueueElement. • These objects will then form the queue using a linked list. • Externally the class has to provide the following public methods: • void enqueue (const string s) which adds strings in the queue (at the tail). • string dequeue () which removes strings from the queue (from the head). • int size () which returns the number of elements in the queue. • bool empty () which checks if the queue is empty. • void clear () which removes all elements from the queue. • Again you have to separate the declaration from the implementation with the use of an appropriate header file • Important: Since you will use dynamic memory allocation, do not forget to appropriately delete the objects using the destructor.

  28. Exercise 1 – Operator Overloading • Overload the operators “<<“ and “>>” in order to add or respectively remove items from the queue. • queue << aString; synonymous with queue.enqueue (aString); • queue >> aString; synonymous with aString = queue.dequeue (); Exercise 1 – Batch Printer • Suppose we have a system that constantly generates output. We do not want to constantly print the output but instead we would like to collect the individual outputs into packages of a predefined size (batch) and as soon as the package is full print it to the output stream. • For this you have to implement a class BatchPrinter

  29. Exercise 1 – Class BatchPrinter • // BatchPrinter.h • #include <iostream> • #include "StringQueue.h" • #ifndef BATCHPRINTER_H_ • #define BATCHPRINTER_H_ • class BatchPrinter { • public: • BatchPrinter(ostream* out, intbatchSize); // Constructor takes as input a pointer to the output stream and • ~BatchPrinter(); // desired batch size. • void add(string aString); // Adds aString to the queue until you reach batch size and call • void flush(); // flush() to write all queued elements to the output stream. • private: • intbatchSize; • StringQueue* q; • ostream* out; • }; • #endif /* BATCHPRINTER_H_ */

  30. Exercise 1 – Class BatchPrinter // BatchPrinter.cpp #include "BatchPrinter.h" BatchPrinter::BatchPrinter(ostream* out, intbatchSize) { this->q = new StringQueue(); this->batchSize = batchSize; this->out = out; } BatchPrinter::~BatchPrinter() { // Delete the queue that was allocated in the constructor. … } // Adds aString to the internal queue. If there are batchSize elements in the queue, flush() is called to write all // queued elements to the output stream. void BatchPrinter::add(string aString) { … } // Writes all elements in the queue to the output stream. After a call to flush() the queue will be empty. void BatchPrinter::flush() { … }

More Related