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
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
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
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