constructors and destructors
play

Constructors and Destructors Invoking Mechanisms Advantage of OOP - PowerPoint PPT Presentation

Contents House Keeping Problem Constructors Destructors Constructors and Destructors Invoking Mechanisms Advantage of OOP Multiple Constructors Array of Objects C++ Object Oriented Programming Default Arguments


  1. Contents  House Keeping Problem  Constructors  Destructors Constructors and Destructors  Invoking Mechanisms  Advantage of OOP  Multiple Constructors  Array of Objects C++ Object Oriented Programming  Default Arguments Pei-yih Ting  Initialization Lists NTOU CS  Constant Data Members Initialization 17-1 17-2 House Keeping Problems Invalid Internal State  What is wrong with these code?  Initialization  Interface functions are required to maintain the internal state of an class Array { void main() { object such that they are valid and consistent all the time. public: Array array; void initArray(int arraySize); array.insertElement(10, 0);  Without suitable initialization, the object’s initial state would be void insertElement(int element, int slot); } invalid. int getElement(int slot) const;  We need a way to guarantee that each new object is well void cleanUp(); private: initialized. No additional care should be taken by the client codes. In the client code: main() int m_arraySize; 1. Forget to initialize the object array  Clean up int *m_arrayData; (there is no call to initArray()) };  Clean up is important if a program is supposed to run for a long 2. Forget to call cleanUp() code segment time. If resources (memory, file, …) are occupied one by one and void Array::initArray(int arraySize) { forget to released afterwards, sooner or later no program would m_arrayData = new int[arraySize]; have enough resources to finish their job correctly. m_arraySize = arraySize; Assume insertElement(), getElement(), }  We need a way to guarantee that each object is well cleaned up. and cleanUp() are defined elsewhere. No additional care should be taken by the client codes. 17-3 17-4

  2. Constructors Destructors  ctor : A constructor is a function executed automatically  dtor : A destructor is a function executed automatically when an object’s life when an object comes into existence. comes to an end. (goes out of scope, program ends, or is deleted dynamically)  Syntax  Syntax  The name of the destructor must be the same as the name of the class preceded  The name of the constructor is the same as the class name by ~ (tilde).  Must not have a return type ~Array();  Parameters must be supplied when the object is defined.  Destructors take no arguments and return no values  Do not call it (explicitly)  Do not call it (explicitly) except the following :  Purpose: to free any resource (memory, file, connection) allocated by the object. 1. new statements, 2. initialization lists, 3. temporary objects class Array { void main() { Array:: ~Array() { class Array public: Array array (20) ; { delete[] m_array; Array(int arraySize); array.insertElement(10, 0); public: } void insertElement(int element, int slot); } … int getElement(int slot) const; void main() { Array::Array(int arraySize) { private: ~Array(); Array array (20) ; m_array = new int[arraySize]; int m_arraySize; … array.insertElement(10, 0); m_arraySize = arraySize; int *m_array; }; } } }; 17-5 17-6 When are ctors and dtors invoked? Advantages Achieved by OOP  Static variables (local, global) codes inserted by the C++ compiler Automatic initialization Reduced memory-leakage risks void Foo() { Array::Array(int arraySize) { Array::~Array() { Array array(20); / / ctor invoked m_array = new int[arraySize]; delete [] m_array; What happens if the dtor m_arraySize = arraySize; array.insertElement(10, 0); } was not defined? } cout << array.getElement(0); } // dtor invoked Safe client/server programming  ctor of a global variable is invoked before main() gets started void Array::insertElement(int element, int slot) { dtor of a global variable is invoked when the program exits if ((slot < m_arraySize) && (slot >= 0)) Better encapsulation  Dynamic variables m_array[slot] = element; What happens if you use else cout << array.getElement(0); malloc() to get the required Array *Foo(int numElements) { memory for an object? cout << "Warning, out of range!!"; Array *array; } array = new Array(numElements); // ctor invoked int Array::getElement(int slot) const { return array; Now, an array is no longer a if ((slot < m_arraySize) && (slot >= 0)) } fixed chunk of data storages. return m_array[slot]; void Bar() { else { It serves data for the client What happens if cout << "Warning, out of range!!"; Array *mainData = Foo(20); codes reliably. It might even we did not call delete? return 0; delete mainData; // dtor invoked adjust its size dynamically. } } } 17-7 17-8

  3. Multiple Constructors Multiple Constructors (cont’d)  A class can have more than one constructor ( function overloading ) void Name::setName(char *firstName, char *lastName) { m_firstName = new char[strlen(firstName)+1]; class Name { m_lastName = new char[strlen(lastName)+1]; public: strcpy(m_firstName, firstName); Name(); strcpy(m_lastName, lastName); Name(char *firstName, char *lastName); ~Name(); } void Name::printName() const { void setName(char *firstName, char *lastName); Name::~Name() { if (m_firstName) cout << m_firstName << ' '; void printName() const; delete[] m_firstName; VC, 『預設建構函式』 if (m_lastName) cout << m_lastName << ' '; private: delete[] m_lastName; } } char *m_firstName; This ctor has special name: char *m_lastName; “ default constructor ”.  Usage: }; void main() { Name name1, name2("Mary", "Smith"); Name::Name() { Name::Name(char *firstName, char *lastName) { name1.setName("Mark", "Anderson"); m_firstName = 0; setName(firstName, lastName); name1.printName(); name2.printName(); m_lastName = 0; } } } 17-9 17-10 Constructors and Arrays Solutions to Array of Objects  Solution 1 : provide a ctor without arguments … i.e. the default ctor  If you want to define an array of objects, your class must have a class Name { default ctor . public: C++ compiler does not give you a ‘default’ if you specify any ctor. Name(); Name() is the default constructor Name(char *firstName, char *lastName); class Name { ~Name(); public: void setName(char *firstName, char *lastName); Name(char *firstName, char *lastName); private: ~Name(); char *m_firstName; void setName(char *firstName, char *lastName); char *m_lastName; private: }; char *m_firstName;  Solution 2 : have no ctor at all … i.e. use the implicit default ctor char *m_lastName; error C2512: 'Name' : no appropriate class Name { }; default constructor available public: void main() { Compiler accepts. ~Name(); Name names[100]; void setName(char *firstName, char *lastName); names[12].setName("Mark", "Anderson"); private: } char *m_firstName; char *m_lastName; Name names[2] = {Name("Mark", "Anderson"), Name("Ron","Dale")}; // OK }; 17-11 17-12

  4. Constructors with Default Arguments Ctor with Default Arguments (cont’d)  Consider this class with two constructors class Account {  The class is rewritten in public: class Account { the following way: Account(double startingBalance Account(double startingBalance); ); public: = 0.0 Account(); void changeBalance(double amount); Account(double startingBalance); void showBalance() const; This ctor is exactly void changeBalance(double amount); private: void main() { the same as before double m_balance; void showBalance() const; Account client1, client2(100.0); private: }; client1.showBalance(); double m_balance; client2.showBalance(); Account::Account(double startingBalance) { }; } m_balance = startingBalance; } Account::Account() { Output: m_balance = 0.0;  We can now declare an array of Account. 0.0 } void main() { This works fine with a 100.0 Account clients[100]; fake default ctor. Account::Account(double startingBalance) { clients[0].changeBalance(100.0); clients[0].showBalance(); m_balance = startingBalance; } } 17-13 17-14 Initialization Lists Constant Data Member Initialization  Consider the class:  Consider the following class  The ctor might look like: class Dog { public: enum Breed {undefined,  The breed of the dog will not change Dog::Dog(char *name, Dog(); collie, poodle, Breed breed, int age) { Dog(char *name, Let us make it a constant variable in coca, bulldog}; m_name = new char[strlen(name)+1]; Breed breed, int age); the class declaration. class Dog { strcpy(m_name, name); ~Dog(); public: m_breed = breed; void list() const ; void list();  Constant variables MUST be Dog(); m_age = age; private: Dog(char *name, initialized in the initialization list } char *m_name; Breed breed, int age); Breed m_breed; const Breed m_breed; Dog::Dog(): m_breed(undefined) {…} ~Dog();  This ctor can be rewritten as: int m_age; private: }; char *m_name; Dog::Dog(char *name, Breed breed, int age)  Other preferred usages of const Breed m_breed; : m_name(new char[strlen(name)+1]), int m_age; m_breed(breed), m_age(age) { Dog::Dog( const char *name, const Breed breed, const int age) }; strcpy(m_name, name); : m_name(new char[strlen(name)+1]), m_breed(breed), m_age(age) { } strcpy(m_name, name); } 17-15 17-16

Recommend


More recommend