6.088-7 Tricks of the trade in C, C++

Add to Favourites
Post to:

6.088 Intro to C/C++Day 6: Miscellaneous TopicsEunsuk Kang & JeanYangIn the last lecture...Inheritance Polymorphism Abstract base classes Today’s topics Polymorphism (again) Namespaces Standard Template Library Copying objects Integer overflow Polymorphism revisitedPolymorphism revisited Recall: Ability of type A to appear as or be used like another type B. Example: Rectangle* r = new Square(5.0); //length = 5.0where Square is a subtype of Rectangle Liskov Substitution Principle Photograph removed due to copyright restrictions.Please see http://www.pmg.csail.mit.edu/~liskov/..Barbara Liskov Winner,Turing Award 08’ If S is a subtype of T, then the behavior of a program P must remain unchanged when objects of type T are replaced with objects of type S. Rectangle-Square example class Rectangle { protected:float length;float width;public:Rectangle(float length, float width);void setLength();void setWidth();void getLength();void getWidth();} class Square : public Rectangle { //representation invariant: length = widthpublic: Square(float length); void setLength(); //ensures length = width void setWidth(); //does nothing } Rectangle-Square exampleclass Rectangle { protected:float length;float width;public:Rectangle(float length, float width);void setLength();void setWidth(); Violates the Liskovvoid getLength(); Substitution Principle. void getWidth(); } Why? class Square : public Rectangle { //representation invariant: length = width public: Square(float length);void setLength(); //ensures length = widthvoid setWidth(); //does nothing} Solutions Ugly: Modify setWidth and setLength in Rectangle to return a boolean. Make them return “true” in Rectangle, and “false” in Square. Define a separate method “setDimension” in Square. Better: Maybe Square shouldn’t really be a subtype of Rectangle? Change the type hierarchy! Think about behaviors, not just characteristics of an object! Solutions Ugly: Modify setWidth and setLength in Rectangle to return a boolean.They always return “true” in Rectangle, and “false” in Square. Define a separate method “setDimension” in Square. Better: Maybe Square shouldn’t really be a subtype of Rectangle? Re-think the type hierarchy! Think about behaviors, not just characteristics of an object! Solutions Ugly: Modify setWidth and setLength in Rectangle to return a boolean.They always return “true” in Rectangle, and “false” in Square. Define a separate method “setDimension” in Square. Better: Maybe Square shouldn’t really be a subtype of Rectangle? Re-think the type hierarchy! Think about behaviors, not just characteristics of an object! NamespacesNamespaces �an abstract space that contains a set of names�useful for resolving naming conflicts namespace ford { class SUV { ... }; } namespace dodge { class SUV { ... }; } int main() { ford::SUV s1 = new ford::SUV(); dodge::SUV s2 = new dodge::SUV(); ... } Using namespacesUse with caution! namespace ford { class SUV { ... };class Compact { ... }; } int main() { using namespace ford; //exposes SUV and Compact SUV s1 = new SUV(); ... } Using namespaces Expose only the things that you need to use!namespace ford { class SUV { ... };class Compact { ... }; } int main() { //using namespace ford; using ford::SUV; SUV s1 = new SUV(); ... } C++ standard library & namespaceC++ standard library includes: �string (std:string s = “Hello World!”) �vector (std::vector ...) �iostream (std::cout << ...) �and many other things! The library lives inside the namespace “std” Using namespace std #include class MITPerson { protected: int id; std::string name; std::string address; public: MITPerson(int id, std::string name, std::string address); void displayProfile(); void changeAddress(std::string newAddress); }; Using namespace std #include class MITPerson { protected: int id; std::string name; std::string address; public: MITPerson(int id, std::string name, std::string address); void displayProfile(); void changeAddress(std::string newAddress); }; Using namespace std #include class MITPerson { protected: int id; I am too lazy to type!std::string name;std::string address; public: MITPerson(int id, std::string name, std::string address); void displayProfile();void changeAddress(std::string newAddress); }; Using namespace std #include using namespace std; class MITPerson { protected: int id; string name; string address; public: MITPerson(int id, string name, string address); void displayProfile(); void changeAddress(string newAddress); }; Using namespace std -Be aware! This is potentially dangerous.Why? Rules of thumb: �“using std::string” instead of “using namespace std” �include “using...” only in the .cc file, not in the header (why?) Simplest rule: Just type “std::”. Sacrifice a few extra keystrokes in the name of good! StandardTemplate Library Standard Template Library (STL) �a set of commonly used data structures & algorithms�parameterized with types Some useful ones include: �vector �map �stack, queue, priority_queue �sort More available at: http://www.cppreference.com/wiki/stl/start Example using vectors�an array with automatic resizingstd::vector v; //creates an empty vector of type T elements std::vector v2(100); std::vector v3(100); //creates a vector with 100 ints //creates a vector with 100 elements primitives initialized to objects created using some default value default constructorStudent class from the last lecture#include #include #include "MITPerson.h" #include "Class.h" class Student : public MITPerson { int course;int year; //1 = freshman, 2 = sophomore, etc.std::vector classesTaken; public: Student(int id, std::string name, std::string address, int course, int year);void displayProfile();void addClassTaken(Class* newClass);void changeCourse(int newCourse);}; A list of classes as a vector#include #include don’t forget! #include "MITPerson.h" #include "Class.h" class Student : public MITPerson { int course; int year; //1 = freshman, 2 = sophomore, etc. std::vector classesTaken; public: Student(int id, std::string name, std::string address, int course, int year); declares an empty vector of void displayProfile();void addClassTaken(Class* newClass);pointers to Class objectsvoid changeCourse(int newCourse);}; Vector operations Class* c1 = new Class(“6.01”);Class* c2 = new Class(“6.005”); //inserting a new element at the back of the vector classesTaken.push_back(c1);classesTaken.push_back(c2);//accessing an elementClass* c3 = classesTaken[0];Class* c4 = classesTaken.at(1);std::cout << c3.getName() << “\n”; //prints “6.01”std::cout << c4.getName() << “\n”; //prints “6.005” //removing elements from the back of the vectorclassesTaken.pop_back();classesTaken.pop_back();//checking whether the vector is emptyif (classesTaken.empty()) std::cout << “Vector is empty!\n”; Vector operations Class* c1 = new Class(“6.01”);Class* c2 = new Class(“6.005”); //inserting a new element at the back of the vector classesTaken.push_back(c1);classesTaken.push_back(c2);//accessing an elementClass* c3 = classesTaken[0];Class* c4 = classesTaken.at(1);std::cout << c3.getName() << “\n”; //prints “6.01”std::cout << c4.getName() << “\n”; //prints “6.005” //removing elements from the back of the vectorclassesTaken.pop_back();classesTaken.pop_back();//checking whether the vector is emptyif (classesTaken.empty()) std::cout << “Vector is empty!\n”; Vector operations Class* c1 = new Class(“6.01”);Class* c2 = new Class(“6.005”); //inserting a new element at the back of the vector classesTaken.push_back(c1);classesTaken.push_back(c2);//accessing an elementClass* c3 = classesTaken[0];Class* c4 = classesTaken.at(1);std::cout << c3.getName() << “\n”; //prints “6.01”std::cout << c4.getName() << “\n”; //prints “6.005” //removing elements from the back of the vectorclassesTaken.pop_back();classesTaken.pop_back();//checking whether the vector is empty if (classesTaken.empty()) std::cout << “Vector is empty!\n”; Vector operations Class* c1 = new Class(“6.01”);Class* c2 = new Class(“6.005”); //inserting a new element at the back of the vector classesTaken.push_back(c1);classesTaken.push_back(c2);//accessing an elementClass* c3 = classesTaken[0];Class* c4 = classesTaken.at(1);std::cout << c3.getName() << “\n”; //prints “6.01”std::cout << c4.getName() << “\n”; //prints “6.005” //removing elements from the back of the vectorclassesTaken.pop_back();classesTaken.pop_back();//checking whether the vector is empty if (classesTaken.empty()) std::cout << “Vector is empty!\n”; Traversing a vector using an iterator//display a list of classes taken by the student //create an iterator std::vector::iterator it; std::cout << "Classes taken:\n"; //step through every element in the vector for (it = classesTaken.begin(); it != classesTaken.end(); it++){ Class* c = *it; std::cout << c->getName() << "\n"; } Classes taken: 6.01 6.005 Traversing a vector using an iterator//display a list of classes taken by the studenttype for the iterator //create an iterator std::vector::iterator it; increment iterator std::cout << "Classes taken:\n"; //step through every element in the vector for (it = classesTaken.begin(); it != classesTaken.end(); it++){ Class* c = *it; std::cout << c->getName() << "\n"; } iterator to the beginning iterator to the end of the vector of the vector Traversing a vector using an iterator//display a list of classes taken by the student //create an iterator std::vector::iterator it; std::cout << "Classes taken:\n"; //step through every element in the vector for (it = classesTaken.begin(); it != classesTaken.end(); it++){ std::cout << c->getName() << "\n"; Class* c = *it; } it a pointer to an element *it the element There are many other functionsCourtesy of C++ Reference. Used with permission. http://www.cppreference.com/wiki/stl/vector/startCopying objectsObjects as values So far we’ve dealt mostly with pointers to objects. What if you want to pass around objects by value? For example, void print(MITPerson p){ p.displayProfile(); } int main() { MITPerson p1(921172, “James Lee”, “32 Vassar St.”); MITPerson p2 = p1; print(p2); } 36Creating an object from another 1. initialization by value, so make a copy void print(MITPerson p){ p.displayProfile(); } 2. pass by value, so make a copy int main() { MITPerson p1(921172, “James Lee”, “32 Vassar St.”); MITPerson p2 = p1; print(p2); } (3. could also return an object as a return value)37 Copying objects using constructorsvoid print(MITPerson p){ p.displayProfile(); } int main() { MITPerson p1(921172, “James Lee”, “32 Vassar St.”); MITPerson p2 = p1; print(p2); } So how do objects get copied?Copy constructors are called.Object::Object(const Object& other) { ... } 38Copy constructor in MITPerson#include class MITPerson { protected: int id; std::string name; std::string address; public: MITPerson(int id, std::string name, std::string address); MITPerson(const MITPerson& other); void displayProfile(); void changeAddress(std::string newAddress); }; 39Defining the copy constructorwhy const? object that you are copying from MITPerson::MITPerson(const MITPerson& other){ name = other.name; id = other.id; address = other.address; } 40Default copy constructor �automatically generated by the compiler �copies all non-static members (primitives & objects)�invokes the copy constructor of member objects MITPerson::MITPerson(const MITPerson& other){ name = other.name; id = other.id; address = other.address; } 41Assigning an object to anotherMITPerson p1(921172, “James Lee”, “32 Vassar St.”); MITPerson p2(978123, “Alice Smith”, “121 Ames St.”); p2 = p1; //assigns p2 to p1, does NOT create a new object So how do objects get assigned to each other? Copy assignment operator is called. Object& Object::operator=(const Object& other) { ... } 42Copy assignment operator in MITPerson#include class MITPerson { protected:int id;std::string name;std::string address; public: MITPerson(int id, std::string name, std::string address); MITPerson(const MITPerson& other); MITPerson& operator=(const MITPerson& other); void displayProfile(); void changeAddress(std::string newAddress); }; 43Defining the copy assignment operatorMITPerson& MITPerson::operator=(const MITPerson& other){ name = other.name; id = other.id; address = other.address; return *this; //returns a newly assigned MITPerson } MITPerson p1(921172, “James Lee”, “32 Vassar St.”); MITPerson p2(978123, “Alice Smith”, “121 Ames St.”); p2 = p1; 44Defining the copy assignment operator MITPerson& MITPerson::operator=(const MITPerson& other){ name = other.name; id = other.id; address = other.address; return *this; } Again, if you don’t define one, the compiler will automatically generate a copy assignment operator So why do we ever need to define copy constructors & copy assignment operators ourselves? 45Default copy constructor -caution!class B { public: void print() { std::cout << "Hello World!\n”; } }; class A { B* pb; int x; public:A(int y) : x (y) { pb = new B(); }~A() { delete pb; } //destructorvoid printB() { pb->print(); }}; void foo(A a) { a.printB(); } int main() { A a1(5); a1.printB(); foo(a1); return 0; } 46Default copy constructor -caution!class B { public: void print() { std::cout << "Hello World!\n”; } }; class A { B* pb; int x; public:A(int y) : x (y) { pb = new B(); }Double free! ~A() { delete pb; } //destructor void printB() { pb->print(); } How do we fix this? }; void foo(A a) { a.printB(); } int main() { A a1(5); a1.printB(); foo(a1); return 0; } 47Default copy constructor -caution!class B { public: void print() { std::cout << "Hello World!\n”; } }; class A { B* pb; int x; public:A(int y) : x (y) { pb = new B(); }A(const A& other) { //copy constructorx = other.x; pb = new B();} ~A() { delete pb; } //destructor A& operator=(const A& other) { //copy assignment operator x = other.x; delete pb; //clean up the junk in the existing object! pb = new B(); return *this; } void printB() { pb->print(); } }; 48Rule of three in C++ If you define any one of the three in a class, then youshould define all three (you will probably need them!)�destructor �copy constructor �copy assignment operator 49Integer overflowBinary search algorithmint binarySearch(int a[], int key, int length) { int low = 0; int high = length -1; while (low <= high) { int mid = (low + high) /2; int midVal = a[mid]; if (midVal < key) low = mid + 1 else if (midVal > key) high = mid -1; else return mid; //key found } return -(low + 1); //key not found} Courtesy of Joshua Bloch. Used with permission. based on from Joshua Bloch’s implementation in java.util51 Binary search bugint binarySearch(int a[], int key, int length) { int low = 0; int high = length -1; while (low <= high) { int mid = (low + high) /2; int midVal = a[mid]; if (midVal < key) low = mid + 1Can you find the bug? else if (midVal > key) high = mid -1; else return mid; //key found } return -(low + 1); //key not foundCourtesy of Joshua Bloch. Used with permission.} 52Binary search bugint binarySearch(int a[], int key, int length) { int low = 0; int high = length -1; while (low <= high) { int mid = (low + high) /2; if (low + high) > MAX_INTEGER, int midVal = a[mid]; it will overflow! if (midVal < key) low = mid + 1dangerous array access! else if (midVal > key)(Java will at least throw high = mid -1; else an exception) return mid; //key found } return -(low + 1); //key not foundCourtesy of Joshua Bloch. Used with permission.} 53One solution Instead of: int mid = (low + high) /2;use:int mid = low + (high -low) /2;Surprisingly, most implementations of the binary search tree had this bug! (including java.util) http://googleresearch.blogspot.com/2006/06/extraexttraread-all-about-it-nearly.html 54ConclusionUseful links Google C++ style guideline http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml C++ FAQ http://www.parashift.com/c++-faq-lite/index.html56There are many things we haven’t told you!Thinking in C++ (B. Eckel) Free online edition!Essential C++ (S. Lippman)Effective C++ (S. Meyers)C++ Programming Language (B. Stroustrup)Design Patterns (Gamma, Helm, Johnson,Vlissides)Object-Oriented Analysis and Design with Applications (G. Booch, et. al)57 Congratulations!Now you know enough about C/C++ to embark on your own journey!58MIT OpenCourseWarehttp://ocw.mit.edu 6.088 Introduction to C Memory Management and C++ Object-Oriented ProgrammingJanuary IAP 2010For information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms.

Description
This lecture notes explores Tricks of the trade and interview questions for C and C++. Things people might see in interviews, etc. Review and discussion of the covered topics, Q&A.

“Eunsuk Kang & Jean Yang, 6.088-7 Tricks of the trade in C, C++ ,6.088 Introduction to C Memory Management and C++ Object-Oriented Programming, Electrical Engineering and Computer Science, Engineering, Massachusetts Institute of Technology: MIT Open Course Ware,http://ocw.mit.edu (22-08-2011).License: Creative Commons BY-NC-SA: http://ocw.mit.edu/terms/#cc".

Comments

Want to learn?

Sign up and browse through relevant courses.

Name:
Your Email:
Password:
Country:
Contact no:


Area code Number
Subjects you are interested in:
Word verification: (Enter the text as in image)


Sign Up Already a member? Sign In
I agree to WizIQ's User Agreement & Privacy Policy
LearnOnline Through OCW
OpenCourseWare
User
102 Followers

Your Facebook Friends on WizIQ

Explore Similar Courses

Program in C++

Price:$149

Give live classes, create & sell online courses

Try it free Plans & Pricing

Connect