EE 4 E C Programming Lecture 2 Classes


































![my. Class: : my. Class(char* m, int len) { message_length=len; message=new char[len]; strcpy(message, m); my. Class: : my. Class(char* m, int len) { message_length=len; message=new char[len]; strcpy(message, m);](https://slidetodoc.com/presentation_image_h2/6652702fff354c437a3b697fe31582d4/image-35.jpg)














- Slides: 49

EE 4 E. C++ Programming Lecture 2 Classes

Contents n n n n Introduction User defined data types Classes and encapsulation Implementation/interface Classes and objects Creating/initializing objects – constructors Destroying objects – destructors Other features of classes

Introduction n Classes are the core of C++’s support for object oriented programming n They allow the programmer to create abstract data types in a similar way that struct does in C u u n However the C++ class also supports encapsulation whereas struct does not Encapsulation allows the programmer to hide details about the implementation First we will review the struct construct

User defined data types C (and C++) allow user defined data types to be created using the struct construct n For example, we could create a Date data type to represent dates n struct Date { int d; int m; int y; };

n We could create variables (objects) of the Date data type as well as writing functions that operate on these objects extern void set_date(Date*, int, int); extern void print_date(const Date*); void main() { Date* date = new Date; set_date(date, 28, 8, 2003) print_date(date); }

n In C++, we can include the functions as part of the struct declaration so they become member functions u This means we don’t have to pass the objects as arguments into the functions struct Date { int d; int m; int y; void set(int, int); void print(); };

n The member functions are defined using the : : operator as follows : void Date: : set(int dd, int mm, int yy) { d=dd; m=mm; y=yy; } void Date: : print() { printf(“Day, month, year = %d %d %d ”, d, m, y); }

n Finally Date objects can be created and member functions called as follows : u Note that member functions are called through the object (variable) name void main() { Date today; today. set(12, 8, 2003) today. print(); }

Classes and encapsulation n Classes in C++ are similar and have similar syntax and uses as structures in C with one key difference u They support the idea of encapsulation u The implementation of the class is hidden from the interface to the class u This is achieved through the use of public and private member access specifiers

n We can define a Date class as follows : class Date { private: int d; int m; int y; public: void set(int, int); void print(); void advance(); };

n An additional member function advance() has been added which advances the date by one day n Apart from that, this has the same functionality as the Date structure n The key difference is the separation of the class into private and public n This separation underpins the ideas behind encapsulation (or implementation/interface)

Key point n Only public member functions of Date can access private members of the class u Enforced by rules of the language u If we try to access a private class member from outside a public member function, a compilation error is triggered

n Implementation of Date: : set() is as follows void Date: : set(int dd, int mm, int yy) { d=dd; m=mm; y=yy; } n Accesses Date: : d, Date: : m, Date: : y which is OK as it’s a public member function

n The following is illegal code int get_year(Date date) { return date. y; // Error! } int main() { Date today; today. d=28; today. m=8; today. y=1998; } n // Error! This is an attempt to access a private class member from outside a public member function

n In order to access the private class members Date: : d, Date: : m, Date: : y, we have to provide public member access functions class Date { private: int d; int m; int y; }; public: void set(int, int); void print(); void advance(); int day() {return d; } // access function int month() {return m; } // access function int year() {return y; } // access function

n You may wonder (quite rightly!) whether this is an undue computational overhead u n In order to access a private class member, we have to go through an additional function call However, access restriction of the classes private members is key to encapsulation u Implementation/interface

Implementation/interface n We can justify the sub-division of a class into private and public by considering the idea of the implementation of the class and the interface to the class n The implementation of the class is represented by the private class members and public member function bodies (which use the private members) n The interface to the class is represented by the public member functions headers

Date private int d int m int y Implementation public void set() void print() void advance() int date() int month() int year() Interface

Changing the implementation of Date n Suppose we decide to change the implementation of Date and represent the date internally in the Julien format u This represents the number of days since 1/1/1900 from which the current day, month and year can be computed algorithmically

class Date { private: long julien; }; // Number of days since 1/1/1900 public: void set(int, int); void print(); void advance(); int day() {// returns d} int month() {// returns m } int year() {// returns y} // access function

The key point is that public member function body implementations need to change to reflect the changed private members n However, the public member function headers remain the same n These represent the interface to the Date class as seen by application programs using the class n

Date : : day() { // complicated algorithm } Date : : month() { // complicated algorithm } Date : : year() { // Simple algorithm (taking into account leap years) } Date: : advance() { julien++; }

Key point Because of encapsulation, applications using the Date class will not change as they only interact with the class through public member function calls n This leads to more robust extendible systems n

n For example, some external function weekend() will still be correct even after the changes to Date u The function interacts with Date through the public member function day() int weekend(Date date) { // Returns true if the date falls on a weekend return ((date. day()==0)||(date. day()==6)); }

Classes and objects Its important to be clear about the distinction between classes and objects n It may seem obvious but it does cause confusion n Essentially an object is an instantiation of a class u We can create many objects of the same class n

n We can create several date objects as follows : Date date; date. set(14, 4, 2003) Date another_date; another_date. set(15, 4, 2003); Date date Apr 14, 2003 Date another_date Apr 15, 2003

n We have 1 class u n n Date We have 2 objects u date u another_date Typically class names will start with upper case and object names will start with lower case

Creating/initializing objects – constructors Objects can be created and initialized by declaring special public member functions called constructors with the same name as the class n A nice feature of constructors is that function overloading can be used so that objects can be initialized in different ways n

class Date { private: int d, m, y; }; public: Date(); // constructor Date(int, int); // constructor Date(char *); // constructor void set(int, int); void print(); void advance(); int day() {return d; } // access function int month() {return m; } // access function int year() {return y; } // access function

n The implementation of the constructors are as follows : Date: : Date() { // default construcotr } Date: : Date(int dd, int mm, int yy) { d=dd; m=mm; y=yy; } Date: : Date(char* date_string) { // Parse the string and assign to d, m, y }

n We can now create and initialize objects as follows : Date tomorrow; // Date() called Date today(1, 9, 1998); // Date(int, int) called Date yesterday("31 st August 1998"); // Date(char*) called

n Note that the constructor is automatically called when an object is declared u u n It doesn’t have to be initialized (although it is usually good practice to do so) However, the default constructor must be present if we wish to create uninitialized objects Note also that we can create objects dynamically and this also involves calling a constructor Date* today = new Date(1, 9, 1998); today->advance();

Destroying objects – destructors n Destructors are member functions which are called automatically (see later) in order to delete an object and release all of the memory taken by that object u n Unlike Java, C++ has no automatic garbage collection For a simple class like Date, no dynamic allocation of private member variables has taken place so the compiler can delete Date objects by simply deleting each private member variable

n For classes where private members have been dynamically allocated, we must implement the destructor in order for the object to be completely deleted class my. Class { private: char* message; int message_length; }; public: my. Class(char* m, int len); ~my. Class(); // constructor // destructor
![my Class my Classchar m int len messagelengthlen messagenew charlen strcpymessage m my. Class: : my. Class(char* m, int len) { message_length=len; message=new char[len]; strcpy(message, m);](https://slidetodoc.com/presentation_image_h2/6652702fff354c437a3b697fe31582d4/image-35.jpg)
my. Class: : my. Class(char* m, int len) { message_length=len; message=new char[len]; strcpy(message, m); } my. Class: : ~my. Class() { delete[] message; }

n Destructors are called automatically when : u The delete operator is called for a dynamically created object u An automatically created object goes out of scope u The program (main) (or a function) terminates for a statically created object u The destructors for globally defined objects are called last of all

Other features of classes n We will look at a few other features of classes u this self-reference u Friends u Static class members

Self-reference - this Each (non-static) member function has a access to a pointer to the instantiated object from which the member function was called (!!) n So, for example, in our Date class, member functions have access to a (constant) pointer of type Date* n

Date private int d int m int y public. . void advance() { // access to this }.

n The following re-implementation of advance() makes a copy of a Date object using a dereferenced this but moved on 1 day Date: : advance() { Date d=*this; // make a copy d. julien++; return d; } Date d(1, 9, 1998); Date new_d=d. advance();

n Thus, a completely new initialized Date object is produced Date new_d 1/9/98 2/9/98

Friends A function or a class can be made a friend of another class u This means that the function or class members can access the private members of the class n Using the friend keyword in a class declaration allows encapsulation to be broken and should be used carefully n

class X {. friend int func(); friend class Y; . }; n This declaration allows func() and all of Y’s member functions to access the private parts of class X n Note that it is the designer of class X who specifies the friend relationships

class Date { private : int d, m, y; }; public : Date(int, int); // constr. . friend int weekend(Date); int weekend(Date date) { return ((date. d==0)||(date. d==6)); // OK! }

Static class members n Each object has its own copy of all non-static date members of a class n A static class members belongs to the class u There is only 1 class wide copy u Useful for maintaining class wide information u static class data members exist even if an object hasn’t been instantiated

n static class members still have private, public privileges u u u n Only static public member functions can access static private members if an object has yet to be instantiated In this case the member function is accessed through the class name using the : : operator Once an object has been instantiated, static members can be accessed through non-static public member functions also static class members must be initialized once and once only before use

n A static class member num_objects can be used to keep a track on the number of objects of a certain class that have been created class my. Class { private : static int num_objects; public : my. Class() { num_objects++; } }; static int get() { return num_objects; }

int my. Class: : num_objects=0; // Initialize static void main() { printf(“num objects so far = %d ”, my. Class: : get()); // prints 0 my. Class m 1; my. Class m 2; my. Class m 3=new my. Class(); printf(“num objects so far = %d ”, my. Class: : get()); // prints 3 }

And finally ……. . n The key message in this lecture is encapsulation and implementation/interface separation n This leads to self-contained software units – classes – which are the basis of object oriented programming n Object oriented applications comprise a set of objects, interacting through their class interfaces n The next lecture looks at inheritance and polymorphism which allow for flexible object behaviour, a key element of OOP