1 / 65

CS3101-2 Programming Languages – C++ Lecture 3

CS3101-2 Programming Languages – C++ Lecture 3. Matthew P. Johnson Columbia University Fall 2003. Agenda. hw1 was due last night Today: Pointer review Classes Operator overloading hw2 TBA tonight. Ptrs, references, and things. int x = 4; //thing &x //address of thing

brianfields
Download Presentation

CS3101-2 Programming Languages – C++ Lecture 3

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. CS3101-2Programming Languages – C++Lecture 3 Matthew P. Johnson Columbia University Fall 2003 CS3101-2, Lecture 2

  2. Agenda • hw1 was due last night • Today: • Pointer review • Classes • Operator overloading • hw2 TBA tonight CS3101-2, Lecture 2

  3. Ptrs, references, and things • int x = 4; //thing • &x //address of thing • int *xp = &x; //ptr to thing • *xp = 10; //thing • int &rx = x; //reference to thing • rx = 11; //thing • x = 12; //same thing: x == rx • int *rxp = ℞ //ptr to thing • *rxp = 13; /*same thing: *rxp == rx == x */ CS3101-2, Lecture 2

  4. Pointer & reference e.g. • int x = 5; int y = 10; int& xr = x; int *yp = &y; rx *= 3; •  x == 15, xr == 15, y == 10, *yp == 10 • *yp = rx; rx++; • x == 16, xr == 16, y == 15, *yp == 15 • yp = ℞ rx++; •  x == 17, xr == 17, y == 15, *yp == 17 CS3101-2, Lecture 2

  5. Composite data • We have primitive vars • individual pieces of data • okay as far as they go • We have arrays: • fixed, but arbitrarily large seq of vars • but only one element type • We also have: structs • complex entities with named members • record with fields: vars, arrays, structs, etc. • access with dot: mystruct.field1 CS3101-2, Lecture 2

  6. struct e.g.: stack • Stack: FILO data structure • ~ stack of trays in lunch room • const int STACK_SIZE = 100; struct Stack { int count; int data[STACK_SIZE]; }; • Struct declarations end with ;! CS3101-2, Lecture 2

  7. stack struct: init, push void stack_init(Stack &stack) { stack.count = 0; } inline void stack_push(Stack &stack, const int item) { stack.data[stack.count++] = item; } NB: • we pass in a reference to our stack • we don’t need “struct Stack” as in C • we set the count-th mem to item; then inc count CS3101-2, Lecture 2

  8. stack struct: pop inline int stack_pop(Stack &stack) { return stack.data[--stack.count]; } NB: • we decrement the count and then return the mem • inline expands ftn-call to ftn content • as though we searched for calls to stack_pop and replaced with its two lines of code • don’t need to add ftn call to C’s call stack • used for fast, often called ftns • replaces CPP macros CS3101-2, Lecture 2

  9. struct stack e.g. • Stack stack; • push_stack(5); • data[count++] = 5  data[0] == 5, count == 1; • push_stack(10); • data[count++] = 10  data[1] == 10, count == 2; • x = pop_stack(); • return data[--count]  count == 1, ret data[1] == 10 • Right? CS3101-2, Lecture 2

  10. struct stack init • Well, no. • In push_stack(5); • we assumed size == 0 but never set •  we write to data[random index] • So we initialize first • Now: Stack stack; init_stack(stack); push_stack(5); … • Q: What if we forget to call init_stack? • A: Don’t! CS3101-2, Lecture 2

  11. More trouble… • Stack s; init_stack(s); int x = pop_stack(s); //empty! • push(s, 2); push(s, 3); init_stack(s); //lost 2 and 3! • s.data[0] = 5; //legal! • s.count = -10; //legal! • Eventually, we run out of room in data CS3101-2, Lecture 2

  12. Classes • Structures are better than nothing, but: • no way to force init at beginning • no way to group all struct’s ftns together • anyone can modify struct’s members • stack.count = -10; • stack.push(5); write to data[-10] • must keep passing struct ref to ftns • must put “stack” in ftn names • Better idea: place all the struct’s ftns inside the struct struct + member ftns == class CS3101-2, Lecture 2

  13. class Stack: declaration/stack.h class Stack { private: // visible only inside the class Stack int count; int data[STACK_SIZE]; public: // visible from anywhere void init(); void push(const int item); int pop(); }; NB: class def must end with a ; • Access modifiers are for sections, not individual mems (as in J) • Sections can come in any order, be repeated, etc. • Default access level is private • Both ftns and data can be both public and private CS3101-2, Lecture 2

  14. class Stack implementation/stack.cpp void Stack::init() { count = 0; } inline void Stack::push(const int item) { data[count++] = item; } inline int Stack::pop() { return data[--count]; } • Like before, but Stack:: before each ftn name CS3101-2, Lecture 2

  15. class Stack e.g. • Stack stack; stack.init(); stack.push(5); stack.push(10); int x = stack.pop(); NB: • Access (public) data and ftns with dot op • Member ftn uses curr inst’s data • Public member ftns provide interface to inst’s data CS3101-2, Lecture 2

  16. class Stack constructor • Class is big improvement over struct • But still must manually call init() after each instantiation • Turns out: can write a constructor(s) • ftn with same name as class • called automatically when class inst created • automatically creates member vars (count, data) • no return type (not void!) • Stack::Stack() { count = 0; } CS3101-2, Lecture 2

  17. class Stack destructor • Conversely, classes can have a (unique) destructor • ftn with name ‘~’ + class name, no return type • called automatically when class inst destroyed • automatically frees class member vars • Not needed for this Stack, but could give error msg: • Stack::~Stack() { if (count != 0) cerr << “Destroying non-empty” << “ stack.\n”; } CS3101-2, Lecture 2

  18. class Stack destructor • Notice destructor name: ~Stack • Bitwise op ~ is the complement op: • applied to int, each bit is flipped • ~1001 == 0110 • 1001 + 0110 == 1111 • constructor + destructor == 0 (well, -1 in 2’s comp) • Intuition: destructor undoes the work of the constructor CS3101-2, Lecture 2

  19. Parameterized constructors • So far, no-param constructor: Stack stack; • Constructors can also take params • Consider an (x,y) point class: • class Point { private: double x, y; public: double getX(), getY(); void setX(), setY(); Point(double a, double b); } Point::Point(double a, double b) { x = a; y = b; } CS3101-2, Lecture 2

  20. Parameterized constructors • Point pt(10,10); • Looks diff from J: Point pt = new Point(10,10); • Reason: C++ classes do not imply dynamic memory! • But if: Point pt; we get an error • If no constructors defined, no-param constructor is automatically defined (simply creating member vars) • Otherwise, must declare/define it ourselves: • class Point { private … public: Point() {}; } • NB: we can define ftns inside the class declaration • usually just for short ftns; automatically inline CS3101-2, Lecture 2

  21. Copy constructors • One special parameterize constructor: one constructor, of class type • Consider: Stack stack1 = stack2; • Q: What happens? • A: The value of a struct/class is composed of/ specified by the vals of all members •  Each mem of stack1 init-ed to corr. mem of stack2 •  stack1.count set to stack2.count; members of stack1.data set to corr. mems of stack2.data CS3101-2, Lecture 2

  22. Copy constructor • Default copy constructor does do this • Think of it as: Stack::Stack(const Stack &that) { for (int i = 0; i < that.count; i++) data[i] = that.data[i]; count = that.count; } • Q: Why can we access private count mem of that? • A: We’re accessing it from the Stack class • Q: What if data were pointing to dynamic memory? • A: Just a minute… CS3101-2, Lecture 2

  23. Copy constructor • Copy constructor is called implicitly: • Stack stack2 = stack1; expands to Stack stack2(stack1); • ()/= equiv applies to primitives as well: • int x(10); • Used, even more implicitly in pass-by-val: • void myftn(Stack local) { … } myftn(stack1); • Used, even more implicitly in temporary return value: • Stack myftn2() { … return someStack; } stack3 = myftn2(); • Lesson 1: copy constructor specifies what we mean by value • Lesson 2: uses references for class params and return values whenever possible CS3101-2, Lecture 2

  24. Assignment operator • Closely related to the copy constructor is the assignment operator • Stack s2 = s1; • copy constructor used to initialize s2 with s1 • Stack s3; s3 = s2; • assignment op used to reset s3 with s2 • Q: Difference? • A: copy const. create member objects and inits; in assign op, member objects already exist • current content must be destroyed so objs can be reset • Assign op also called implicitly: • stack3 = myftn2(); • Show tdstack.cpp CS3101-2, Lecture 2

  25. Copy const, assign op, destructor • By default, copy constructor and assignment op do natural thing: copy each member var • “shallow copy” • Usually need one iff need all three • Usually need all three iff using dynamic memory CS3101-2, Lecture 2

  26. Default member ftns • Classes have built-in, default no-param constructor, destructor, copy constructor, assignment op • Suppose want to disallow use of one • Soln 1: Print message when called: • class Stack { public: Stack(const Stack &that) { cerr << “not allowed\n”; } } } • But we only find out at runtime CS3101-2, Lecture 2

  27. Prevent constructor call • Soln 2: Make constructor private: • class Stack { private: Stack(Stack &that) {} … } • Now call to copy constructor (outside of Stack) will not compile CS3101-2, Lecture 2

  28. structs v. classes • Turns out: structs in C++ can contain member ftns as well • Further turns out: only difference between classes and C++ structs is: • default class access level: private • default class access level: public • otherwise, struct and class can technically be used interchangeably CS3101-2, Lecture 2

  29. Where do classes live? • Generally, 1 class ~ 2 files: • .h: header/interface/declaration • .cpp: implementation • Header contains • class Stack { void ftn2(); int ftn2(); } • .cpp contains • void Stack::ftn1() { … } • int Stack::ftn2() { … } CS3101-2, Lecture 2

  30. Where do classes live? • .cpp files for classes used are compiled along with other .cpp files: • g++ myproj.cpp stack.cpp • .h files for classes used are included with CPP: • include <iostream> • include “stack.h” • For uses-written headers (at least), include line is replaced with file content •  multiple includes can cause trouble CS3101-2, Lecture 2

  31. Multiple includes • Suppose our program includes both stack.h and stackutil.h • But stackutil.h includes stack.h • #include “stack.h” #include “stackutil.h” •  • #include “stack.h” #include “stack.h” … •  • class Stack { … } class Stack { …} …  error CS3101-2, Lecture 2

  32. Multiple includes • We prevent this problem with a (rare) use of CPP • The content of every .h file is surrounded by: • #ifndef _FILENAME_H #define _FILENAME_H //actual content #endif • The first time filename.h is included in a file, we define _FILENAME_H and include the content • Any future time, _FILENAME_H is recognized, so we jump to the #endif •  there’s no more code, so the include has no effect CS3101-2, Lecture 2

  33. Conts & pts review • Remember: type-expr *p means that when p is dereferenced, we get something of type type-expr • So Q: what are: • const int *cip = &x; int const *cip = &x; • A: ptr-to-const • Q: What is: • int *const IP = &x; • Q: const ptr • Q: What are: • const int *const CIP; int const *const CIP; • A: const ptr-to-const CS3101-2, Lecture 2

  34. const vars • Constant primitive vars are immutable • like const primitives in C, final primitives in Java • const double PI = 3.14; PI = 4; error/warning • Constant objects more complicated • const string s = “hi”; s = “there”; error • s.at(0)++;  error s.append(“abc”);  error • Value of object  values of all members •  Cannot change indy mems or assign (change all mems) • NB: Java’s reference/content distinction doesn’t arise here • in J: objects vars always ref vars • final String s = …;  cannot reassign s; mutability of contents determined by class • C++ has non-ref objects  const refers to object content CS3101-2, Lecture 2

  35. const objects • Only constant member ftns can be called on const objects: • class MyString { private: … public: int size() const; // not const int size(); void append(const char *str); int &at(int pos) const; } • On const object: • can call size • cannot call append • can call at, but its result will refer to a const CS3101-2, Lecture 2

  36. const data members • Classes can contain const data members • Init-ed with special syntax in constructor • class MyMath { public: const double PI = 3.14; // does not compile! const double PI; const double E; MyMath() : PI(3.14), E(2.71) {} … } • We don’t have this restriction for … static members CS3101-2, Lecture 2

  37. Static members • Suppose want to keep track of total current number of instances of some class in existence • each time we construct, inc total • each time we destruct, dec total • Class con/destructor have access to this total • but not specific to any instance • member of class, not of an instance thereof • Big idea: static data is part of the cookie cutter • non-static data is part of a particular cookie CS3101-2, Lecture 2

  38. Static data members • class Stack { public: static insts = 0; //init-ed once Stack() { insts++; } ~Stack() { insts--; } } • Stack s; // Stack::insts == 1 if (1 == 1) { Stack stacks[10]; // Stack::insts == 11 } // Stack::insts == 1 • Access static members with ClassName::MEM • Can also use standard instance.MEM • but considered impolite CS3101-2, Lecture 2

  39. statics • Also: straightforward init of static consts is allowed • since unchanging, most static members can be class members • class MyMath { private: static const PI = 3.14; … } • Member ftns can also be static: • class Stack { private: static insts = 0; public: static int getInstCount(); … } • Can access insts through getter: • Stack::getInstanceCount() • Static ftns can only access static data members CS3101-2, Lecture 2

  40. Meanings of “static” • File-level var/ftn: not visible outside of file • second construal: var init-ed only once • external makes visible outside file (although this is the default) • Local var (in a ftn): var init-ed only once • not for each ftn call • Var in a class: var init-ed only once • not for each class instance • Ftn in a class: can access only static data members CS3101-2, Lecture 2

  41. Operator overloading • Overloading: multiple behaviors for the same syntax • Operator overloading: defining behavior of an operator when applied to a class • E.g, +/- applies to built-in numerical types • When we define our Point class, representing an (x,y) point •  can overide +/- to behave appropriately • (2,3) + (5,5) == (7,8) (picture vectors) CS3101-2, Lecture 2

  42. Point class • class Point { private: double x, y; public: double getX(), getY(); Point() : x(0), y(0) {} Point(double xx, double yy) : x(xx), y(yy) {} Point(const Point &that) : x(that.x), y(that.y) {} Point operator+(const Point& that); Point operator-(const Point& that); Point operator-(); … } CS3101-2, Lecture 2

  43. Adding points • Point p1(3,4), p2(10,10); • Point p3 = p1 + p2; •  error: + not defined • Point Point::operator+(const Point& that) { Point temp; temp.x = this->x + that.x; temp.y = this->y + that.y; return temp; } • p1 + p2 expands to p1.operator+(p2) CS3101-2, Lecture 2

  44. Adding points’ • Same behavior, more succinct • Point Point::operator+(const Point& that) { return Point(this->x + that.x, this->y + that.y); } • Text uses this bad/no-OOP style: • Point Point::operator+(const Point& that, const Point& that2) { return Point(this.x + that2.x, that.y + that2.y); } • Poor style – not allowed in homework! CS3101-2, Lecture 2

  45. Operator overloading • Now p1 + p2 works; Suppose p1 + 5? • Should this be allowed? Does it make sense? • Maybe we want: (x,y) + 5 == (x+5,y+5) • Then can overload thus: • Point Point::operator+(const int v) { return Point(this->x + v, this->y + v); } CS3101-2, Lecture 2

  46. Operator overloading • Now p1 + 5 works; Q: does 5 + p1 work? • A: No: would expand to 5.operator+(p1), which doesn’t exist • Instead, must write global ftn with two params • Point operator+(int v, Point& that) { return Point(v + that.x, v + that.y); } • Problem: x, y are inaccessible here • Soln 1: use a friend function CS3101-2, Lecture 2

  47. Friend functions • A class can declare another class or ftn its friend •  the friend can access private members of the class • NB: A declaring B its friend  B has access to A, not other way around •  friendship is not transitive! • class Point { … friend Point operator+(int v, Point& that); } CS3101-2, Lecture 2

  48. x, y inaccessible • Soln 2: Provide getters to x, y • class Point { public: double getX(), getY(); … } • but we don’t always want to make data publicly accessible • Soln 3: use existing + op: • Point operator+(int v, Point& that) { return that + v; } CS3101-2, Lecture 2

  49. Operator overloading • Can override all standard math ops: • + - * / • etc. • Can override [] • Interp here? maybe [0]  x, [1]  y • double Point::operator[](int pos) { return pos == 0 ? x : y; } • C++ smart enough to convert p[i] to p.operator[](i) CS3101-2, Lecture 2

  50. Overloading << • Suppose want to print a point • Non-OO: manually extract, then print each double • OO: pass to stream; design to behave appropriately • ostream& operator<<(ostream& out, const Point& pt) { out << “(“ << pt.x << “,” << pt.y << “)”; return out; } • Here, op<< must be a friend or use getters • op<< must return the stream for cascaded outputs: • cout << “my point: ” << pt;  op<<(cout, “my point :”) << pt  op<<(op<<(cout, “my point :”), pt)  op<<(cout, pt)  cout CS3101-2, Lecture 2

More Related