Chapter 9 - Chapter 9 Chapter Technicalities: Classes, etc....

Info iconThis preview shows page 1. Sign up to view the full content.

View Full Document Right Arrow Icon
This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: Chapter 9 Chapter Technicalities: Classes, etc. Bjarne Stroustrup www.stroustrup.com/Programming Cambridge Cambridge Stroustrup/Programming 2 ISO C++ standards committee ISO Stroustrup/Programming 3 CERN CERN Stroustrup/Programming 4 Abstract Abstract This lecture presents language technicalities, This mostly related to user defined types; that is, classes and enumerations. classes Stroustrup/Programming 5 Overview Overview Classes Implementation and interface Constructors Member functions Enumerations Operator overloading Stroustrup/Programming 6 Classes Classes The idea: A class directly represents a concept in a program If you can think of “it” as a separate entity, it is plausible that If it could be a class or an object of a class it Examples: vector, matrix, input stream, string, FFT, valve Examples: controller, robot arm, device driver, picture on screen, dialog box, graph, window, temperature reading, clock box, A class is a (user-defined) type that specifies how class objects of its type can be created and used objects In C++ (as in most modern languages), a class is the In key building block for large programs key And very useful for small ones also The concept was originally introduced in Simula67 Stroustrup/Programming 7 Members and member access Members One way of looking at a class; class X { // this class’ name is X // this // data members (they store information) // data // function members (they do things, using the information) // function }; Example class X { public: int m; // data member data int mf(int v) { int old = m; m=v; return old; } // function member int function }; X var; var.m = 7; var.m int x = var.mf(9); // var is a variable of type X // // access var’s data member m // access data // call var’s member function mf() // call member Stroustrup/Programming 8 Classes Classes A class is a user-defined type class X { public: // this class’ name is X // this // public members -- that’s the interface to users // public that’s // (accessible by all) // functions // types // data (often best kept private) private: // private members -- that’s the implementation details // private that’s // (accessible by members of this class only) (accessible // functions // types // data }; Stroustrup/Programming 9 Struct and class Struct Class members are private by default: class X { int mf(); // … // }; Means class X { private: int mf(); // … // }; So X x; int y = x.mf(); // variable x of type X // of // error: x is private (i.e., inaccessible) // error: Stroustrup/Programming 10 Struct and class Struct A struct is a class where members are public by default: struct X { int m; // … // }; Means class X { public: int m; // … // }; structs are primarily used for data structures where the are members can take any value members Stroustrup/Programming 11 11 Structs Structs Date: my_birthday: y m // simplest Date (just data) // simplest struct Date { int y,m,d; // year, month, day // year, }; Date my_birthday; d // a Date variable (object) // variable my_birthday.y = 12; my_birthday.m = 30; my_birthday.d = 1950; // oops! (no day 1950 in month 30) // oops! // later in the program, we’ll have a problem // later Stroustrup/Programming 12 Structs Structs Date: my_birthday: y m // simple Date (with a few helper functions for convenience) // struct Date { int y,m,d; // year, month, day // year, }; Date my_birthday; d // a Date variable (object) // variable // helper functions: // helper void init_day(Date& dd, int y, int m, int d); // check for valid date and initialize void check void add_day(Date&, int n); // … // increase the Date by n days // increase init_day(my_birthday, 12, 30, 1950); // run time error: no day 1950 in month 30 run Stroustrup/Programming 13 Structs Structs Date: my_birthday: y m d 1950 12 30 // simple Date // // guarantee initialization with constructor // guarantee // provide some notational convenience struct Date { int y,m,d; // year, month, day Date(int y, int m, int d); // constructor: check for valid date and initialize constructor: check void add_day(int n); // increase the Date by n days increase }; // … // Date my_birthday; Date my_birthday(12, 30, 1950); Date my_day(1950, 12, 30); my_day.add_day(2); my_day.m = 14; // error: my_birthday not initialized // my_birthday // oops! Runtime error // oops! // ok // ok // January 1, 1951 // January // ouch! (now my_day is a bad date) // my_day Stroustrup/Programming 14 Classes Classes Date: my_birthday: y m d 1950 12 30 // simple Date (control access) // class Date { int y,m,d; // year, month, day // year, public: Date(int y, int m, int d); // constructor: check for valid date and initialize Date(int constructor: check // access functions: // access void add_day(int n); // increase the Date by n days increase int month() { return m; } int int day() { return d; } int int year() { return y; } }; // … // Date my_birthday(1950, 12, 30); cout << my_birthday.month() << endl; my_birthday.m = 14; my_birthday.m Stroustrup/Programming // ok // ok // we can read // // error: Date::m is private // Date::m 15 Classes Classes The notion of a “valid Date” is an important special case of the The idea of a valid value idea We try to design our types so that values are guaranteed to be valid Or we have to check for validity all the time A rule for what constitutes a valid value is called an “invariant” The invariant for Date (“Date must represent a date in the past, present, or The future”) is unusually hard to state precisely future”) Remember February 28, leap years, etc. If we can’t think of a good invariant, we are probably dealing with If plain data plain If so, use a struct Try hard to think of good invariants for your classes that saves you from poor buggy code Stroustrup/Programming 16 Classes Classes Date: my_birthday: y m 1950 12 30 // simple Date (some people prefer implementation details last) d // class Date { public: Date(int y, int m, int d); // constructor: check for valid date and initialize Date(int constructor: check void add_day(int n); // increase the Date by n days increase int month(); // … // private: int y,m,d; // year, month, day // year, }; Date::Date(int yy, int mm, int dd) :y(yy), m(mm), d(dd) { /* … */ }; :y(yy), // definition; note :: “member of” // definition; // note: member initializers // note: void Date::add_day(int n) { /* … */ }; // definition definition Stroustrup/Programming 17 Classes Classes Date: my_birthday: y 1950 12 30 m // simple Date (some people prefer implementation details last) d // class Date { public: Date(int y, int m, int d); // constructor: check for valid date and initialize Date(int constructor: check void add_day(int n); // increase the Date by n days increase int month(); // … private: int y,m,d; // year, month, day // year, }; int month() { return m; } // error: forgot Date:: Date:: // this month() will be seen as a global function will // not the member function, can’t access members // not int Date::season() { /* … */ } int // error: no member called season season Stroustrup/Programming 18 Classes Classes // simple Date (what can we do in case of an invalid date?) // simple class Date { public: class Invalid { }; // to be used as exception // to Date(int y, int m, int d); // check for valid date and initialize // check // … private: int y,m,d; // year, month, day // year, bool check(int y, int m, int d); // is (y,m,d) a valid date? // is }; Date:: Date(int yy, int mm, int dd) Date(int : y(yy), m(mm), d(dd) { if (!check(y,m,d)) throw Invalid(); } Stroustrup/Programming // initialize data members // initialize // check for validity // check 19 Classes Classes Why bother with the public/private distinction? Why not make everything public? To provide a clean interface To maintain an invariant Only a fixed set of functions can access the data To ease debugging Data and messy functions can be made private Only a fixed set of functions can access the data (known as the “round up the usual suspects” technique) To allow a change of representation You need only to change a fixed set of functions You don’t really know who is using a public member Stroustrup/Programming 20 Enumerations Enumerations An enum (enumeration) is a very simple user-defined An enum type, specifying its set of values (its enumerators) type, For example: enum Month { jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec }; Month m = feb; m = 7; // error: can’t assign int to Month // error: to int n = m; // ok: we can get the numeric value of a Month // ok: Month mm = Month(7); // convert int to Month (unchecked) // convert (unchecked) Stroustrup/Programming 21 Enumerations Enumerations Simple list of constants: enum { red, green }; int a = red; enum { red, blue, purple }; // the enum { } doesn’t define a scope // enum // red is available here // is // error: red defined twice red Type with list of constants enum Color { red, green, blue, /* … */ }; enum enum Month { jan, feb, mar, /* … */ }; Month m1 = jan; Month m2 = red; Month m3 = 7; int i = m2; // error red isn’t a Month // error isn’t // error 7 isn’t a Month // error isn’t // ok: an enumerator is converted to its value, i==0 // ok: Stroustrup/Programming 22 Enumerations – Values Enumerations By default // the first enumerator has the value 0, the // the next enumerator has the value “one plus the value of the // the // enumerator before it” enumerator enum { horse, pig, chicken }; // horse==0, pig==1, chicken==2 // horse==0, You can control numbering enum { jan=1, feb, march /* … */ }; // feb==2, march==3 enum // feb==2, enum stream_state { good=1, fail=2, bad=4, eof=8 }; int flags = fail+eof; // flags==10 // flags==10 stream_state s = flags; // error: can’t assign an int to a // error: an to stream_state stream_state stream_state s2 = stream_state(flags); // explicit conversion (be careful!) // explicit Stroustrup/Programming 23 Classes Classes Date: 1950 my_birthday: y 12 m 30 d // simple Date (use Month type) // simple class Date { public: enum Month { jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec }; Date(int y, Month m, int d); // check for valid date and initialize Date(int check // … private: int y; // year // year Month m; int d; // day day }; Date my_birthday(1950, 30, Date::dec); Date my_birthday(1950, Date::dec, 30); Stroustrup/Programming // error: 2nd argument not a Month // error: Month // ok // ok 24 Const Const class Date { public: // … // int day() const { return d; } void add_day(int n); // … // }; // const member: can’t modify // const // non-const member: can modify // non- Date d(2000, Date::jan, 20); const Date cd(2001, Date::feb, 21); cout << d.day() << " – " << cd.day() << endl; d.add_day(1); // ok ok cd.add_day(1); // error: cd is a const // error: is Stroustrup/Programming // ok ok 25 Const Const // Date d(2004, Date::jan, 7); const Date d2(2004, Date::feb, 28); d2 = d; // error: d2 is const // error: const d2.add(1); // error d2 is const // d2 d = d2; // fine // fine d.add(1); // fine // fine // a variable // variable // a constant // constant d2.f(); // should work if and only if f() doesn’t modify d2 // should doesn’t // how do we achieve that? (say that’s what we want, of course) // how Stroustrup/Programming 26 Const member functions Const // Distinguish between functions that can modify (mutate) objects // Distinguish // and those that cannot (“const member functions”) // and class Date { public: // … int day() const; // get (a copy of) the day // // … // void add_day(int n); // move the date n days forward // move // … }; const Date dx(2008, Month::nov, 4); int d = dx.day(); // fine // fine dx.add_day(4); // error: can’t modify constant (immutable) date // error: Stroustrup/Programming 27 Classes Classes What makes a good interface? Minimal Complete And no smaller Type safe As small as possible Beware of confusing argument orders Const correct Stroustrup/Programming 28 Classes Classes Essential operations Default constructor (defaults to: nothing) No default if any other constructor is declared Copy constructor (defaults to: copy the member) Copy assignment (defaults to: copy the members) Destructor (defaults to: nothing) For example Date d; // error: no default constructor // error: Date d2 = d; // ok: copy initialized (copy the elements) // ok: d = d2; // ok copy assignment (copy the elements) // ok Stroustrup/Programming 29 Interfaces and “helper functions” Interfaces Keep a class interface (the set of public functions) Keep minimal minimal Simplifies understanding Simplifies debugging Simplifies maintenance When we keep the class interface simple and When minimal, we need extra “helper functions” outside the class (non-member functions) the E.g. == (equality) , != (inequality) next_weekday(), next_Sunday() Stroustrup/Programming 30 Helper functions Helper Date next_Sunday(const Date& d) { // access d using d.day(), d.month(), and d.year() // and // make new Date to return // make to } Date next_weekday(const Date& d) { /* … */ } Date bool operator==(const Date& a, const Date& b) { return a.year()==b.year() && a.month()==b.month() && a.day()==b.day(); } bool operator!=(const Date& a, const Date& b) { return !(a==b); } Stroustrup/Programming 31 Operator overloading Operator You can define almost all C++ operators for a You class or enumeration operands class that’s often called “operator overloading” enum Month { jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec }; Month operator++(Month& m) // prefix increment operator // prefix { m = (m==dec) ? jan : Month(m+1); // “wrap around” // “wrap return m; } Month m = nov; ++m; // m becomes dec // becomes ++m; // m becomes jan // becomes Stroustrup/Programming 32 Operator overloading Operator You can define only existing operators You can define operators only with their conventional number You of operands of int operator+(int,int); // error: you can’t overload built-in + Vector operator+(const Vector&, const Vector &); // ok Advice (not language rule): E.g., no unary <= (less than or equal) and no binary ! (not) no <= An overloaded operator must have at least one user-defined An type as operand type E.g., + - * / % () ^ ! & < <= > >= Overload operators only with their conventional meaning + should be addition, * be multiplication, be access, () be call, etc. () Advice (not language rule): Don’t overload unless you really have to Stroustrup/Programming 33 ...
View Full Document

Ask a homework question - tutors are online