lecture04: Largely based on slides by Cinda Heeren CS 225 UIUC 13th June, 2013
Announcements lab debug due Saturday night (6/15) mp1 due Monday night (6/17)
Warmup: what happens? /** @file main.cpp */ void changegrade(student stu) if(stu.getgrade() == F ) stu.setgrade( A ); void main() Student s; s.setgrade( F ); while(s.getgrade() == F ) changegrade(s); /** @file student.h */ #ifndef STUDENT_H #define STUDENT_H class Student public: void setgrade(char letter); char getgrade() const; private: char grade; ; #endif
Another warmup: what happens here? PNG* allocate(size_t w, size_t h) PNG ret(w, h); return &ret; int main() PNG* image = allocate(256, 512); image->writetofile("blank.png"); delete image; return 0;
Motivation are a mechanism for running a function during an object s creation They are not explicitly called; rather, the system invokes them when required If no constructors are written, a default no-argument constructor is provided by the system Sphere s(4.0); Student joe("joe Ciurej", A ); Student chase("chase Geigle", D ); Student tom("tom Bogue", Q );
Writing constructors /** @file sphere.h */ #ifndef SPHERE_H #define SPHERE_H class Sphere public: Sphere(double newradius); void setradius(double newradius); private: double radius; ; #endif /** @file sphere.cpp */ #include "sphere.h" Sphere::Sphere(double newradius) radius = newradius; Sphere::setRadius(double newradius) radius = newradius;
A shortcut for constructors Usually, constructors just set a bunch of variables. Therefore, there is a succint syntax called an initializer list that does just that: // one-parameter constructor Sphere::Sphere(double newradius): radius(newradius) /* nothing */ // "default" constructor sets the radius to zero Sphere::Sphere(): radius(0.0) /* nothing */ // this constructor takes two arguments Sphere::Sphere(double newradius, const std::string & newcolor): radius(newradius), color(newcolor) /* nothing */ Note that we still need the braces after the function declaration even if there are no statements in the function.
Course staff is questionable What should the two-parameter constructor look like to enable the following functionality of the Student class? Student jason("jason Cho", F ); Can you write both implementations: initializer list and function body? Hint: Jason Cho is a string object.
Notes on constructors If you write any constructor, the system no longer provides a default constructor If you do not set member variables in the constructor, their values will be uninitialized...so you should always set all your member variables in the constructor!
Motivation: what happens here? /** @file sphere.h */ #ifndef SPHERE_H #define SPHERE_H /** @file main.cpp */ #include "sphere.h" void main() Sphere s(4.0); // or... class Sphere public: Sphere(double newradius); private: double* radius; ; #endif Sphere* s = new Sphere(4.0); delete s; /** @file sphere.cpp */ #include "sphere.h" Sphere::Sphere(double newradius) radius = new double(newradius);
Our first destructor /** @file sphere.h */ #ifndef SPHERE_H #define SPHERE_H class Sphere public: Sphere(double newradius); ~Sphere(); private: double* radius; ; #endif /** @file sphere.cpp */ #include "sphere.h" Sphere::Sphere(double newradius) radius = new double(newradius); Sphere::~Sphere() delete radius;
, not deconstructors are the opposite of constructors: they are run when an object on the stack goes out of scope or when an object on the heap is deleted are not explicitly called by the user; the system calls them as necessary Think of it this way: calling delete on a pointer to an object on the heap invokes the destructor If your object allocates any dynamic memory, then you need a destructor!
The Collage class /** @file collage.h */ #ifndef COLLAGE_H #define COLLAGE_H #include <iostream> #include "png.h" using namespace std; class Collage public: Collage(size_t numpics); ~Collage(); private: PNG* pics; ; /** @file collage.cpp */ #include "collage.h" Collage::Collage(size_t numpics) cout << "Created!" << endl; pics = new PNG[numPics]; Collage::~Collage() cout << "Destructed!" << endl; delete [] pics; #endif
What is printed in each of these functions? void onstack() cout << "Creating A..." << endl; Collage cola(24); cout << "Creating B..." << endl; Collage colb(12); void onheap() Collage* col = new Collage(4); delete col;
Bonus: RAII Resource Acquisition is Initialization (RAII) is a C++ idiom The constructor acquires a resource, and the destructor frees it Useful for writing exception-safe C++ code Examples: Controlling locks in multithreaded applications Opening files (acquiring file descriptors) Smart pointers Can you think of any more?