C++
Alexander Baltatzis
Recap
• Undefined behaviour
– int * q1 = new int[2];
delete q1;
– int * q2 = new int;
delete [] q2;
• Contract with the compiler constructor
– How would you implement delete []
• Classes with dynamic memory
– The rule of three
Class design
• How should the class be initiated/assigned
• Constructors and destructors
• What operators and functions make sense to implement?
• What functions should be disallowed?
Postponing variable definitions
• Basically the same idea as operator= (see narrated lecture on construction)
• Don’t declare until you can initialize the variable
• string encrypted(password);
Classical problem
Widget w;
for (int i = 0; … w = foo(i);
…
for (int i = 0; … Widget w(foo(i));
…
• What costs more assignment or constructor/destructor?
• Sometimes it’s better to measure afterwards
• In this case, if you’ve written the Widget class you should probably be able to answer
Exercise
• How should a singleton class be designed?
• Make your mind about construction, assignment, copying and inheritance
– Singleton s1, s2;
– s1 = s2;
– Singleton s3 = s1;
– class BetterSingleton : Singelton { …
Factories
• A method constructs the objects
– Complex createComplexFromPolar
(double r, double fi) {…
– Complex createComplexFromCartesian (double x, double y) {…
What about returning pointers?
BigC * p1 = makeBigC(); // delete ?
auto_ptr<BigC> p2(makeBigC());
auto_ptr<BigC> p3 = p2; // How to copy?
tr1::shared_ptr<BigC> p4(makeBigC());
Sometimes you want to return a null (0) value
– Database value – To indicate fault
Using references
• Efficiency
– int calc(Matrix m) { …
– int calc(const Matrix & m) { …
– int calc(int a, const int & b) { … // ?
• Avoid slicing
– void draw(BaseClass b) { …
– void draw(const BaseClass & b) …
• Use as return values
– bool doStuff(Customers & c, Agents & a) {…
• Avoid pointer arithmetics
What about returning referencs
• Almost always wrong
• Except when forcing a static construction
DBInit & create() { static DBInit x;
return x;
}
• DBInit & ref = create();
Code Static data Heap Stack
Class design
Constructing a date class
Date today;
Date d1(25, 12, 2007);
Date d2(12, 25, 2007);
Date d3 = d1 + 3; // OK int daysGone = d3 – d1; // OK d1 + d2 // ??
(d1 + 5) – d3 // ??
d1.addyear(3); // ??
d1.addmonth(2); // ??
Date d(13); // ??
Class design
• The functions should be reasonable
• Allowed operations should make sense
• Can I use inheritance?
– Chinese d2; // today – Persian d1; // today – int zero = d1 – d2;
– Gregorian d3 = d2 + 10;
Date as base class
• Recap – make the destructor virtual?
• There is no dynamic memory
• Rule of three does not apply (but beware)
• What do we know of future subclasses?
How to inherit?
Date
?
Persian Gregorian
Date
Persian Gregorian
Where do I put the code?
Date
Persian
Gregorian
Beware of rule of three
• Gregorian (Date &) {
do_something_important();
}
// Discuss the following lines Persian p;
Gregorian g = p;
Persian p2 = g;
Gregorian g2 = g;
How to construct a date
Suppose we allow the following constructions
Date d3;
Date d4(5, 3);
Date d5(25);
How to construct a date
Suppose we allow the following constructions Date d3; // today
Date d4(5, 3); // 5/3 current year
Date d5(25); // 25th current month
Date(int d=0, int m=0, int y=0) {…
// Why is this constructor a bad idea?
Compile time vs runtime
• Do you prefer compile time error or runtime error?
Date d(Day(1), Month(2), Year(2003));
Date d(Month(2), Day(1),, Year(2003));
Date d(Day(1), Month::Jan(), Year(2007));
struct Month {
static Month Jan() { return Month(1); } static Month Jan() { return Month(1); }
…
private:
explicit Month(int x) : month(x) {}
int month;
}
• static methods to make sure it is initialized
• Explicit constructor to avoid implicit conversions Always consider explicit on
one-argument constructors!
Compile time vs runtime
Date d(1, 1, 2007);
Date d(Day(1), Month::Jan(), Year(2007));
• What are the benefits?
• The first one is easier to type
• The first one is seamingly easier to guess
• The second one catches errors in compile time !!
• Always prefer compile time error checking
Exposing data
• Sometimes a struct is a struct
struct coord {
float x; float y; };
• Sometimes you need to change it
struct coord {
double x; double y; };
• Sometimes it’s not what you think
struct coord {
double q1; double q2; }; // radius, fi
Exposing data
• Prefer day() instead of m_day
• Exposing m_day, month, year commits!
• We cannot change internal representation!
• date as number of days from a fixed date
– 1970-01-01, 1900-01-01, Julian day
• Or as day. month, year?
Encapsulate data
• Hide data from other programmers
• Let them access via accessors/inspectors
• Let them change via mutator functions
• Incedently that’s one of the cornerstones of object oriented programming
• Another cornerstone being organizing the code, put functions that handle the data together with the data (in the same class)
Class design of a calendar
Calendar c;
c.setdate(24, 12, 2007);
c.add_event(”Buy gifts, if you haven’t already!!!”);
c.add_event(”Meeting”, 2007, 5); // when is // that?
void setdate(int d = -1, m = -1, y = -1) {…
Still a very bad idea, discuss!
Why a bad idea
• The programmer did not have to explicitly write 4 functions (12 code lines?)
• He probably saved 6 minutes (2 lines/minute)
• The debugging programmer is looking for a valid date that shouldn’t be in the
calendar in runtime …
• probably had to spend more than 6 minutes looking for the cause
Exercise - Design a calendar class
• How to construct the class?
• What operations is allowed (+ - * etc)?
• What functions do I want?
– Compare with what I can do with a simple calendar paperback booklet?
• How do I handle a Persian calendar?
– Can I convert my scheduled meetings in Iran?
– Can I merge persian and chinese appointments?
Generic programming
• Sometimes your functions apply to more than one type
• What do you need to know when sorting a container?
• You need to know how to compare the items inside
• STL uses iterators to point into containers.
std::sort assumes operator< is implemented
• If it is not implemented we get a compile error
Generic programming benefits
• Reusing code
– one sort implemetation
• Compile time checking
– operator< missing
• Optimization in runtime
– Can optimize containers for simple types
Generic programming
• Instantiate your calendar with the type it should handle
– Calendar<Persian> persian_calendar;
– Calendar<Gregorian> gregorian_calendar;
– gregorian_calendar += persian_calendar; // !!
Dependencies
Event
Event e (Date (Day(1), Month::Jan(), Year(2008)), ”Happy new year”);
• Let’s define an event consisting of a date and some description string.
• How shall I store the string and the date internally?
On the stack
class Event { Date date;
string description;
… }
Code Static data Heap Stack descdate
As an instance
member the date will be allocated on the stack
It might improve performance
Compile dependancy
• Constructing the date object on the stack requires knowledge in compile time. How big is the object to put on the stack?
• It requires a compilation dependancy.
Build time will increase
• An alternative is to use a pointer
Compile time dependancies
• To remove the compile dependancy make the member variable a pointer
• A pointer can always be allocated on the stack without knowing the size of the object it points to.
class Event {
auto_ptr<Date> date;
…
Performance
• The actual date object will be on the heap
• It might take a while to fetch it in runtime
• On the other hand it might be cached
Do not make decisions on assumptions
Test performance with a profiler
Until next time
• Object oriented programming
– Important concepts
• is a
• has a
• Object modelling
– Several solutions possible
– fuzzy (flummigt) subject, sometimes religous
• Extra thinking in lab2
– Apply ”is a” and ”has a” on Date, Calendar, Event