Software Engineer Interview Preparation: One Hour C++ for C Engineers

1 Software Engineer Interview Preparation: One Hour C++ f...
Author: Morgan McKinney
0 downloads 1 Views

1 Software Engineer Interview Preparation: One Hour C++ for C EngineersBy: Marina K. Lam 4/13/2012 Version 2.00

2 References “Ivor Horton’s Beginning Visual C++ 2010”, by Ivor Horton.“Sams Teach Yourself C++”, by Jesse Liberty, Siddhartha Rao, Bradley Jones. “Effective C++ Third Edition”, by Scott Meyers. “Call Stack”, “The virtual table”, by Alex, Feb. 8, 2008 4/13/2012 Version 2.00

3 Problematic Pointer IssuesThe errors you create a program with pointers can be among the most difficult to find and among the most problematic. (Ref: “Sams Teach Yourself C++”, by Jesse Liberty, Siddhartha Rao, Bradley Jones, ch 8) 4/13/2012 Version 2.00

4 Background: The Stack and the Free Store (Heap)There are five areas of memory: Global namespace: global variables are in the global namespace Registers: registers are used for internal housekeeping functions, such as keeping track of the top of the stack and the instruction pointer. Code space: code is in code space The stack: a call stack consists of local variables, function parameters and return address. The stack is cleaned automatically when a function returns. All the local variables go out of scope and they are removed from the stack. The free store (heap): All remaining memory is given to the free store, which is often referred to as the heap. The free store is not cleaned until your program ends, and it is your responsibility to free any memory that you’ve reserved when you are done with it. 4/13/2012 Version 2.00

5 Background: Call Stack (Ref: http://en.wikipedia.org/wiki/Call_stack)A call stack is composed of stack frames (also called activation records or activation frames). These are machine dependent data structures containing subroutine state information. Each stack frame corresponds to a call to a subroutine which has not yet terminated with a return. For example, if a subroutine named DrawLine is currently running, having been called by a subroutine DrawSquare, the top part of the call stack might be laid out like the diagram on the right. The stack frame at the top of the stack is for the currently executing routine. The stack frame usually includes at least the following items: the arguments (parameter values) passed to the routine (if any) the return address back to the routine's caller (e.g. in the DrawLine stack frame, an address into DrawSquare's code) space for the local variables of the routine (if any) 4/13/2012 Version 2.00

6 Dynamic memory allocation: new, delete[]When your program is executed, there is unused memory in your computer. This unused memory is called the “heap” in C++, or sometimes the “free store”. You can allocate space within the free store for a new variable of a given type using “new” operator that returns the address of the space allocated. The operator “delete” de-allocates the memory allocated by “new”. class CMessage { private: char *pMessage; // Pointer to object text string public: void ShowIt() const { cout << endl << pMessage; } // Constructor definition with const char pointer CMessage(const char* text = "Default message") pMessage = new char[strlen(text) + 1]; strcpy_s(pMessage, strlen(text) + 1, text); } ~CMessage() }; // Destructor to free memory allocated by new CMessage::~CMessage() delete [] pMessage; // Free memory assigned to pointer 4/13/2012 Version 2.00

7 Dynamic memory allocation: new, delete[]Of course, the memory may not have been allocated because the free store had been used up, or because the free store is fragmented by previous usage– meaning that there isn’t sufficient number of contiguous bytes to accommodate the variable for which you want to obtain space. You don’t have to worry too much about this because the new operator will throw an exception if the memory cannot be allocated for any reason, which terminates your program. 4/13/2012 Version 2.00

8 Memory leak Case 1 It is critical to remember that memory allocated with “new” is not freed automatically. If a pointer variable is pointing to memory on the free store (heap) and the pointer goes out of scope, the memory is not automatically returned to the free store. Rather, it is considered allocated and because the pointer is no longer available, you can no longer access the memory. This happens, for instance, if a pointer is a local variable. When the function in which that pointer is declared returns, that pointer goes out of scope and is lost. The memory allocated with new is not freed—instead, it becomes unavailable. This situation is called a memory leak. It’s called a memory leak because that memory can’t be recovered until the program ends. It is as though the memory has leaked out of your computer. 4/13/2012 Version 2.00

9 Memory Leak Case 1 (cont.)To prevent memory leaks, you should restore any memory you allocate back to the free store. You do this by using the keyword delete. For example: Animal * pDog; pDog = new Animal; // allocate memory : // Caution:When you delete a pointer, you should set it to zero (null). // Calling delete on a null pointer is guaranteed to be safe. delete pDog; // frees the memory pDog= 0; // sets pointer to null delete pDog; Most commonly, you will allocate items from the heap in a constructor, and deallocate them in the destructor. In other cases, you will initialize pointers in the constructor, deallocate memory for those pointers as the object is used, and, in the destructor, test the pointers for null and decallocate them, if they are not null. 4/13/2012 Version 2.00

10 Memory Leak Case 2 Memory leaks are one of he most serious issues and complaints about pointers. Another way you might inadvertently create a memory leak is by reassigning your pointer before deleting the memory to which it points. unsigned short int * pPointer = new unsigned short int; *pPointer = 72; // Caution: You need to delete the first pPointer memory. If not, // the memory that 72 is now held is unavailable because the // pointer to that area of memory has been reassigned. No way // to free the memory before the program ends. The correction // is to add “delete pPointer” before another new statement. pPointer = new unsigned short int; *pPointer = 84; 4/13/2012 Version 2.00

11 Stray, Wild or Dangling PointersA stray pointer (also called a wild or dangling pointers) is created when you can delete on a pointer—thereby freeing the memory that it points to– and then you don’t set it to null. If you try to use that pointer again without reassigning it, the result is unpredictable and, if you are lucky, your program will crash. Solution: After you have delete a pointer, set the pointer to zero (null). If not, the pointer stills point to the old area of memory, but the compiler is free to put other data there; using the pointer without reallocating new memory for it can cause your program to crash. Worse, your program might proceed merrily on its way and crash several minutes later. This is called a time bomb, and it is no fun. To be safe, after you delete a pointer, set it to null(0). This disarms the pointer. 4/13/2012 Version 2.00

12 Stray pointer typedef unsigned short int USHORT; #include int main() { USHORT * pInt = new USHORT; *pInt = 10; delete pInt; long *pLong = new long; *pLong = 90000; // Error: the following 20 // is assigned to the memory // that pInt points to, but pInt // no longer points anywhere // valid. The memory that pInt // points to was freed by the // call to “delete pInt.” // Assigning a value to that // memory is certain disaster. *pInt = 20; delete pLong; return 0; } 4/13/2012 Version 2.00

13 Using const Pointers Tip: look to the right of the keyword const to find out what is being declared constant: const int *pOne; pOne is a pointer to a constant integer. The value that is pointed to can’t be changed. int * const pTwo; pTwo is a constant pointer to an integer. The integer can be changed, but pTwo can’t point to anything else. const int * const pThree; pThree is a constant pointer to a constant integer. The value that is pointed to can’t be changed, and pThree can’t be changed to point to anythin else. void f1(const Widget *pw) // f1 takes a pointer to a constant Widget void f2 (Widget const *pw) //f2 also takes a pointer to a constant Widget 4/13/2012 Version 2.00

14 Tips for using PointersDo Don’t Do protect objects passed by reference with const if they should not be changed. Do set pointers to null rather than leaving them uninitialized or dangling. Don’t use a pointer that has been deleted. Don’t delete pointers more than once. 4/13/2012 Version 2.00

15 Item 3: Use const whenever possibleDeclaring something const helps compilers detect usage errors, const can be applied to objects at any scope, to function parameters and return types, and to member functions as a whole. Compilers enforce bitwise constness, but you should program using logical constness. When const and non-const member functions have essentially identical implementations, code duplication can be avoided by having the non-const version call the const version. 4/13/2012 Version 2.00

16 Item 3: Avoiding duplication in const and Non-const member functionsSample We want to non-const operator[] to call the const one., but if, inside the non-const operator[], we just call operator[], we’ll recursively call ourselves. class TextBlock{ public: const char& operator[](std::size_t position) const { return text[position]; } char& operator[](std::size_t position) // Just calls const op[] return const_cast( //cast away const on op[]’s return type; static_cast(*this)[position] //add const to *this’s type; call const version of op[] ); }; To avoid infinite recursion, we have to specify that we want to call the const operator[], but there is no direct way to do that. Instead, we cast *this from its native type of TextBlock& to const TextBlock&. Use a static_cast to convert from a non-const object to const one. Use a const_cast to convert a const object to non-const. 4/13/2012 Version 2.00

17 Exploiting References“Sams Teach Yourself C++”, by Jesse Liberty, Siddhartha Rao, Bradley Jones, ch 9 4/13/2012 Version 2.00

18 What is a Reference? A reference is an alias: when you create a reference, you initialize it with the name of another object, the target. int & rSomeRef = someInt; // OK int &rSomeRef = someInt; // OK Warning: When pointers are not initialized or when they are deleted, they ought to be assigned to null (0). This is not true for references because they must be initialized to what they reference when they are declared. 4/13/2012 Version 2.00

19 Passing Function Arguments by ReferenceFunctions have two limitations: Arguments are passed by value, and the return statement can return only one value. Solution: In C++, passing a variable by reference is accomplished in two ways: using pointers and using references. Passing an object by reference enables the function to change the object being referred to. When a function is passed a value by reference (using either pointers or references), the address of the original object is put on the stack, not the entire object. In fact, on some computers, the address is actually held in a register and nothing is put on the stack. In either case, because an address is being passed, the compiler now knows how to get to the original object, and changes made by the function are made there and not in a local copy. 4/13/2012 Version 2.00

20 Passing by Reference for efficiencyEach time you pass an object into a function by value, a copy of the object is made. Each time you return an object from a function by value, another copy is made. This copy-step results in zero to little loss in performance for small objects such as integers. However, with larger, user-created objects such as struct or class objects, the cost of copying can be very high. It is very expensive in performance and memory consumption for copying a massive structure onto the stack. Another cost occurs: with the classes you create, each of these temporary copies is created when the compiler calls a special constructor: the copy constructor. When the temporary object is destroyed, which happens when the function returns, the object’s destructor is called. If an object is returned by the function by value, a copy of that object must be made and destroyed as well. 4/13/2012 Version 2.00

21 Knowing when to use references versus pointersDon’s use reference Do pass parameters by reference whenever possible. Do use const to protect references and pointers whenever possible. Don’t use pointers if references will work. Don’t try to reassign a reference to a different variable. You can’t. 4/13/2012 Version 2.00

22 Common Error: returning out-of-scope object referencesTip Error Remember that a reference is always an alias to some other object. If you pass a reference into or out of a function. Be certain that the object still exists. #include int & GetInt(); int main() { int & rint = GetInt(); return 0; } int & GetInt() int nLocalInt = 25; //Error: the local object, nLocalInt, // is destroyed. The reference returned //by this function is an alias to a //nonexistent object. return nLocalInt; 4/13/2012 Version 2.00

23 Object-oriented Programing (OOP)To support the principles of object-oriented programming, C++ has the following three OOP characteristics: Encapsulation Polymorphism inheritance 4/13/2012 Version 2.00

24 OOP: Encapsulation Encapsulation is the mechanism that binds together code and the data it manipulates, and keeps both safe from outside interference and misuse. In an object-oriented language, code and data may be combined in such a way that a self-contained “black box” is created. When code and data are linked together in this fashion, an object is created. In other words, an object is the device that supports encapsulation. 4/13/2012 Version 2.00

25 What is a class? #pragma once #include using std::cout; using std::endl; class Cbox // Base Class { public: // Function to show the volume of an object void ShowVolume() const { cout << endl << "CBox usable volume is " << Volume(); } // Virtual Function to calculate the volume of a CBox object virtual double Volume() const { return m_Length*m_Width*m_Height; } // Constructor CBox(double lv = 1.0, double wv=1.0, double hv=1.0) : m_Length(lv), m_Width(wv), m_Height(hv) {} protected: double m_Length; double m_Width; double m_Height; }; Class forms the basis for OOP. The class is used to define the nature of an object, and it is C++’s basic unit of encapsulation. 4/13/2012 Version 2.00

26 Inline ImplementationThe keyword inline appears before the return type. You can also put the definition of a function into the declaration of the class, which automatically makes that function inline. inline int Cat::GetWeight() { return itsWeight; //return the Weight data member } #include class Cat { public: Cat (int initialAge, int initialWeight); ~Cat(); int GetAge() const { return itsAge; } // inline int GetWeight(); void SetAge (int age) { itsAge = age; } // inline void Meow() const { std::cout << "Meow.\n"; } // inline private: int itsAge; int itsWeight; }; inline int Cat::GetWeight() return itsWeight; //return the Weight data member } 4/13/2012 Version 2.00

27 Including const Member FunctionsIf you declare a class method const, you are promising that the method won’t change the value of any of the members of the class. To declare a class method constant, put the keyword const after the parentheses enclosing any parameters but before the semicolon ending the method declaration. int GetAge() const { return itsAge; } // inline int GetWeight() const; inline int Cat::GetWeight() const { return itsWeight; //return the Weight data member } #include class Cat { public: Cat (int initialAge, int initialWeight); ~Cat(); int GetAge() const { return itsAge; } // inline int GetWeight() const; void SetAge (int age) { itsAge = age; } // inline void Meow() const { std::cout << "Meow.\n"; } // inline private: int itsAge; int itsWeight; }; inline int Cat::GetWeight() const return itsWeight; //return the Weight data member } 4/13/2012 Version 2.00

28 Base and Derived ClassesA base class is any class that you use as a basis for defining another class. For example, if you define a class, CGlassBox, directly in terms of a class, CBox, CBox is said to be a direct base class of CGlassBox. class CGlassBox: public CBox// Derived class { public: // Virtual function to calculate the volume of a // CGlassBox virtual double Volume() const { return 0.85*m_Length*m_Width*m_Height; } // Allowed to inherit base class protected // members CGlassBox(double lv, double wv, double hv) :CBox(lv, wv, hv) {} // Constructor }; 4/13/2012 Version 2.00

29 What is an object? Object is an instance of a Class that has a runtime state, and is associated with certain specific methods that can change its state. #include #include "GlassBox.h" // For CBox and CGlassBox using std::cout; using std::endl; int main() { CBox myBox(2.0, 3.0, 4.0); //Declare a base box CGlassBox myGlassBox(2.0, 3.0, 4.0); // Declare derived box myBox.ShowVolume(); // display volume of base box myGlassBox.ShowVolume(); // display volume of derived box cout << endl; return 0; } 4/13/2012 Version 2.00

30 What is public, protected, private?Public, protected, private are access specifiers that is used to implement encapsulation of data at various level. 4/13/2012 Version 2.00

31 Public, private, protected access specifierPublic: The members are accessible outside of the class Private: the members are inaccessible outside of the class. Access to the class's private methods and data members is barred to all but the class's own member functions (and friend functions which will be discussed later) (Note: if you have no access specifier for the base class in the definition of a derived class, the default specification is private.) Protected: the members are accessible only to derived class. 4/13/2012 Version 2.00

32 OOP: Inheritance and protected membersWhen a member of a class is declared as protected, that member is not accessible by other, nonmember elements of the program. With one important exception, access to a protected member is the same as access to a private member—it can be accessed only by other members of its class. The sole exception to this is when a protected member is inherited. In this case, a protected member differs substantially form a private one. 4/13/2012 Version 2.00

33 Private vs Protected memberA private member of a base class is not accessible by other parts of your program, including any derived class. However, protected members behave differently. If the base class is inherited as public or private, then the base class protected members become protected members of the derived class, and are, therefore, assessible by the derived class. By using protected, you can create class members that are private to their class but that can still be inherited and accessed by a derived class. 4/13/2012 Version 2.00

34 The access level of inherited class membersClass CBox Class CABox: public Cbox Class CABox: protected CBox Class CABox: private CBox public: Public: Protected: Private: protected: private: No access- ever 4/13/2012 Version 2.00

35 Derived class can access the protected member of public base class.// Box.h in Ex9_07 #include using std::cout; using std::endl; class CBox { public: // Function to show the volume of an object void ShowVolume() const { cout << endl << "CBox usable volume is " << Volume(); } // Function to calculate the volume of a CBox object virtual double Volume() const { return m_Length*m_Width*m_Height; } // Constructor CBox(double lv = 1.0, double wv=1.0, double hv=1.0) :m_Length(lv), m_Width(wv), m_Height(hv) {} protected: double m_Length; double m_Width; double m_Height; }; class CGlassBox: public CBox // Derived class { public: // Function to calculate the volume of a CGlassBox // using protected members of public base class virtual double Volume() const { return 0.85*m_Length*m_Width*m_Height; } // Constructor CGlassBox(double lv, double wv, double hv) :CBox(lv, wv, hv) {} }; // Ex9_13.cpp: Using a nested class to define a stack int main() CBox myBox(2.0, 3.0, 4.0); //Declare a base box CGlassBox myGlassBox(2.0, 3.0, 4.0); // Declare derived box - same size myBox.ShowVolume(); // display volume of base box myGlassBox.ShowVolume(); // display volume of derived box cout << endl; return 0; } 4/13/2012 Version 2.00

36 Derived class can access the protected member of private base class.// Demonstration of Private Inheritance #include using namespace std; class ElectricMotor { public: ElectricMotor () {}; virtual ~ElectricMotor () {}; void StartMotor() Accelerate (); Cruise(); } void StopMotor() speed = 0; cout << "Motor stopped at speed = " << speed << endl; private: void Accelerate () speed = speed + 50; cout << "Motor started speed = " << speed << endl; void Cruise() cout << "Motor running at constant speed = " << speed << endl; // Protected specifier allows the private inheritance derived class Fan to // access protected item. If speed is set to private specifier, compiler // error is found in derived Fan class for accessing private item speed. protected: int speed; }; class Fan : private ElectricMotor { public: Fan () { speed = 0; }; ~Fan() { speed = 0; }; void StartFan () { StartMotor(); } void StopFan () { StopMotor(); } }; int main() Fan mFan; mFan.StartFan(); mFan.StopFan(); /* Note: the next two lines access the base class ElectricMotor. However, * as Fan features 'private inheritance' from ElectricMotor, neither the base class * instance nor its public methods are accessible to the the user of class Fan. * Un-comment them to see a compile failure. */ //mFan.Accelerate(); //ElectricMotor *pMotor = &mFan; } 4/13/2012 Version 2.00

37 Constructor and DestructorConstructor is the member function of the class which has the same name as that of class and it is invoked whenever the class object is instantiated. Using constructor we can allocate memory. Destructor is also the member function of same class name and has ~ operator when ever declared in the function and it is used to destruct the object which has been constructed, whenever we want to destroy it. 4/13/2012 Version 2.00

38 What is a default constructor?Constructor with no arguments or all the arguments have default values. CBox() // Default constructor {} 4/13/2012 Version 2.00

39 What is a default Destructor?All the object that you have been using up to now have been destroyed automatically by the default destructor for the class. The default destructor is always generated automatically by the compiler if you do not define your own class destructor. The default destructor doesn’t delete objects or object members allocated by the operator “new”. ~Cbox() { cout << “Destructor called.” << endl;} 4/13/2012 Version 2.00

40 Making a Constructor Explicitexplicit Cbox(double side): m_Length(side), m_Width(side), m_Height(side) {} Cbox box; box = 99.0; 4/13/2012 Version 2.00

41 OOP: Polymorphism C++ supports polymorphism, which is characterized by the phrase “one interface, multiple methods.” For example, you might have a program that defines three different types of stacks. One stack is used for integer values, one for character values, and one for floating-point values. Because of polymorphism, you can define one set of names, push() and pop(), that can be used for all three stacks. 4/13/2012 Version 2.00

42 Function overloading C++ enables several functions of the same name to be defined, as long as these functions have different sets of parameters ( at least as far as their types are concerned). This capability is called function overloading. When an overloaded function is called, the C++ compiler selects the proper function by examining the number, types and order of the arguments in the call. Function overloading is commonly used to create several functions of the same name that perform similar tasks but on different data types. For example: void function_test(); void function_test(int); void function_test(double); void function_test(int, int); 4/13/2012 Version 2.00

43 Operator overloading Operator overloading is a very important capability because it enables you to make standard C++ Operators, such as +, -, *, and so on, work with objects of your own data types. These are the operators that you can’t overload: :: Scope resolution operator ?: Condition operator . Direct member selection operator sizeof Size-of operator .* De-reference pointer to class member operator 4/13/2012 Version 2.00

44 What is “this” pointer? The “this” pointer is a pointer accessible only within the member functions of a class, struct, or union type. It points to the object for which the member function is called. (Note: Static member functions do not have a this pointer.) class CBox { Double Volume() const Return m_Length*m_Width*m_Height; } public: bool operator>(const CBox& aBox) const; //overload “greater than” Return this->Volume() > aBox.Volume(); Private: double m_Length; double m_Width; double m_Height; }; int main() CBox smallBox(4.0, 2.0, 3.0); CBox mediumBox(10.0, 4.0, 2.0); if (mediumBox > smallBox) cout << “mediumBox is bigger than smallBox); return 0; 4/13/2012 Version 2.00

45 Overloaded assignment operator using dynamic memory allocation// Overloaded assignment operator for CParameter objects // 1st_param = 2nd_param CParameters& operator=(const CParameters aP) { if (this == &aP) // Check adddresses, if equal return *this; // return the 1st operand //Release memory for 1st operand m_Param = aP.m_Param; delete [] pParam; pParam = new int[m_Param]; // Copy 2nd parameter values to 1st for (int i=0; i 4/13/2012 Version 2.00

46 Overloading the Addition Operator// Function to add two Cbox objects CBox Cbox:: operator+(const Cbox& aBox) const { return CBox( m_Length > aBox.m_Length?m_Length : aBox.m_Length, m_Width > aBox.m_Width?m_Width : aBox.m_Width, m_Length > aBox.m_Height?m_Height : aBox.m_Height); } int main() CBox smallBox (4.0, 2.0, 1.0); CBox mediumBox (10.0, 4.0, 2.0); Cbox aBox; aBox = smallBox + mediumBox; return 0; 4/13/2012 Version 2.00

47 Copy constructor Constructor which initializes the it’s object member variables (by shallow copying) with another object of the same class. If you don’t implement one in your class, then compiler implements one for you. Boo Obj1(10); Boo Obj2(Obj1); // calling boo copy constructor Boo Obj2 = Obj1; // calling boo copy constructor 4/13/2012 Version 2.00

48 Copy Constructor By default, when an object is used to initialize another, C++ performs a bitwise copy. That is, an identical copy of the initializing object is created in the target object. It can, at times, be a source of trouble. For example: if an object used as an argument allocates memory and frees that memory when it is destroyed, then its local copy inside the function will free the same memory when its destructor is called. 4/13/2012 Version 2.00

49 Copy Constructor To solve the type of problem just described, C++ allows you to create a copy constructor, which the compiler uses when one object initializes another. Thus, your copy constructor bypasses the default bitwise copy. The most common general form of a copy constructor is: classname (const classname &0) { // body of constructor } 4/13/2012 Version 2.00

50 Copy Constructor is a constructor that creates an object by initializing with an existing object of the same class CBox::CBox(const CBox& initB) // copy constructor { m_Length = initB.m_Length; m_Width = initB.m_Width; m_Height = initB.m_Height; } int main() { CBox box1(2.0, 3.0, 4.0); CBox box2 = box 1; Cbox box3(box1); return(0); } 4/13/2012 Version 2.00

51 OOP: Inheritance Inheritance is the means by which you can define a new class in terms of one you already have. Derived class: When you define one class based on an existing class, the new class is referred to as a derived class. A derived class automatically contains all the data members of the class that you used to define it and, with some restrictions, the function members as well. The class is said to inherit the data members and function members of the class on which it is based. The only members of a base class that are not inherited by a derived class are: the destructor, constructors and any member functions overloading the assignment operator. All other function members. together with all the data members of a base class, are inherited by a derived class. Note: the derived class always has its own constructors and destructor. Base class: A base class is any class that you use as a basis for defining another class. You can arrange to call a particular base class constructor from the derived class constructor. For example: CBase::Display() This enables you to initialize the base class data members with a constructor other than the default, or, indeed, to choose to call a particular class constructor, depending on the data supplied to the derived class constructor. 4/13/2012 Version 2.00

52 Virtual Function A virtual function is a function in a base class that is declared using the keyword virtual. If you specify a function in a base class as virtual and there is another definition of the function in a derived class, it signals to the compiler that you don't want static linkage for this function. What you do want is the selection of the function to be called at any given point in the program to be based on the kind of object for which it is called. 4/13/2012 Version 2.00

53 Virtual Function (cont.)The virtual function of the derived class hides the base case virtual function. If you want to call the base class virtual function, you have to use “CBase::Display()”. 4/13/2012 Version 2.00

54 Abstract class has a pure virtual functionPure Virtual Functions: To define a virtual function in a base class so that it may be redefined in a derived class to suit the objects of that class, but that there is no meaningful definition you could give for the function in the base class. virtual double Volume() const = 0; //pure virtual function A class containing a pure virtual function is called an abstract class. It's called abstract because you can't define objects of a class containing a pure virtual function. It exists only for the purpose of defining classes that are derived from it. If a class derived from an abstract class still defines a pure virtual function of the base as pure, it, too, is an abstract class. Also, a abstract class can have both data members and function members. 4/13/2012 Version 2.00

55 Abstract class has a pure virtual function// Once the abstract virtual destructor is // defined. All the derived classes // are automatically virtual, even though //you don't explicitly specify them as such. virtual ~CContainer() { cout << "CContainer destructor called" << endl;} }; // Container.h for Ex9_10 #pragma once #include using std::cout; using std::endl; class CContainer //Abstract base class with // pure virtual function { public: // Function for calculating a volume - no content // This is defined as a 'pure' virtual function, // signified by '=0' virtual double Volume() const = 0; // pure virtual function // Function to display a volume virtual void ShowVolume() const cout<< endl << "Volume is " << Volume(); } 4/13/2012 Version 2.00

56 Virtual function sample// Header file Box.h in project Ex9_01 #pragma once //Ensures the definition of CBox appears only //once in a build #include "Container.h" #include using std::cout; using std::endl; class CBox: public CContainer // Derived class { public: // Function to show the volume of an object virtual void ShowVolume() const cout << endl << "CBox usable volume is " << Volume(); } // Virtual Function to calculate the volume of a // CCandyBox object virtual double Volume() const { return m_Length*m_Width*m_Height; } CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0): m_Length(lv), m_Width(wv), m_Height(hv) {} // Copy constructor CBox(const CBox& initB) { cout << endl << "CBox copy constructor called"; m_Length = initB.m_Length; m_Width = initB.m_Width; m_Height = initB.m_Height; } ~CBox() { cout << "CBox destructor called" << endl;} protected: double m_Length; double m_Width; double m_Height; // Definition: Friend function are not members of // the class but the Friend function can access all // the members of a class. // Friend function friend double BoxSurface(CBox aBox); }; // Friend function to calculate the surface area of a Box object double BoxSurface(CBox aBox) return 2.0* (aBox.m_Length*aBox.m_Width + aBox.m_Length*aBox.m_Height + aBox.m_Height*aBox.m_Width); 4/13/2012 Version 2.00

57 Derived class copy constructor: when you write a copy constructor for an object of a derived class, you are responsible for ensuring that the members of the derived class object are properly initialized. This includes the inherited class. That is, you have to call the base class copy constructor. class CCandyBox: public CBox // Derived class { public: char* m_Contents; // Virtual Function to calculate the volume virtual double Volume() const { return 1.2*m_Length*m_Width*m_Height; } // Can access Base class protected members // but cannot access Base class private members CCandyBox(double lv, double wv, double hv, char* str = "Candy") : CBox(lv, wv, hv) // Constructor m_Contents = new char [ strlen(str) + 1 ]; strcpy_s(m_Contents, strlen(str) + 1, str); } CCandyBox(char* str = "Candy") // Constructor // Derived class copy constructor: CCandyBox(const CCandyBox& initCB): CBox(initCB) // Call the base class copy constructor { cout << endl << "CCandyBox copy constructor called"; // Get new memory m_Contents = new char[ strlen(initCB.m_Contents) + 1]; strcpy_s(m_Contents, strlen(initCB.m_Contents) + 1, initCB.m_Contents); } ~CCandyBox() // Destructor cout << "CCandyBox Destructor is called" << endl; delete[] m_Contents; }; 4/13/2012 Version 2.00

58 How Virtual Function Work?When a derived object is created, first the constructor for the base class is called and then the constructor for the derived class is called. When a virtual function is created in an object, the object must keep track of that function. Many compilers build a virtual function table, called a v-table. One of these is kept for each type, and each object of that type keeps a virtual table pointer (called a vptr or v-pointer) that points to that table. 4/13/2012 Version 2.00

59 Because there are 3 classes here, the compiler will set up 3 virtual tables: one for Base, one for D1, and one for D2. class Base { public: FunctionPointer *__vptr; virtual void function1() {}; virtual void function2() {}; }; class D1: public Base class D2: public Base 4/13/2012 Version 2.00

60 Listing 11.9 Multiple Virtual Functions called in turn (Sams teach yourself C++, p.324)#include using namespace std; class Mammal { public: Mammal(): itsAge(1) {} virtual ~Mammal() {} virtual void Speak() const {cout << “Mammal speak!\n”;} protected: int itsAge; } class Dog : public Mammal void Speak() cost {cout<< “Woof!\n”;} //Override virtual function }; class Cat : public Mammal void Speak() cost {cout<< “Meow!\n”;} //Override virtual function int main() { Mammal* theArray[3]; Mammal* ptr; int choice, i; for (I =0; i<3; i++) cout << “(1) dog (2) cat: “; cin >> choice; switch (choice) case 1: ptr = new Dog; break; case 2: ptr = new Cat; default: ptr = new Mammal; } theArray[i] = ptr; for (i=0; i<5; i++) theArray[i] ->Speak(); return 0; Result: Woof! Meow! Mammal Speak! 4/13/2012 Version 2.00

61 p.328 4/13/2012 Version 2.00

62 Use Virtual function will increase the class object size by 50-100%If the Point class contains a virtual function, objects of Point class will increase in size. On a 32-bit architecture, they’ll go from 64 bits (for the two ints) to 96 bits (for the ints plus the vptr); on a 64-bit architecture, they may go from 64 to 128 bits, because pointers on such architectures are 64 bits in size. Therefore, the Point objects cannot fit in a 64-bit register. class Point { public: Point(int xCoord, int yCoord); ~Point(); private: int x , y; }; 4/13/2012 Version 2.00

63 Why does C++ not have a virtual constructor and a virtual copy constructor?C++ does not support such thing as a virtual constructor. Technically, no such thing exists as a virtual copy constructor. Your program desperately needs to be able to pass in a pointer to a base object and have a copy of the correct derived object that is created. A common solution to this problem is to create a Clone() method in the base class and to make it virtual. The Clone() method creates a new object copy of the current class and returns that object. 4/13/2012 Version 2.00

64 Common Question: When to use Virtual Destructor?It is legal and common to pass a pointer to a derived object when a pointer to a base object is expected. What happens when that pointer to a derived subject is deleted? If the destructor is virtual, as it should be, the right thing happens—the derived class’s destructor is called. Because the derived class’s destructor automatically invokes the base class’s destructor, the entire object is properly destroyed. Due to the increase in size of abstract base class, the rules of thumb for virtual destructor are: Polymorphic base classes should declare virtual destructors. If a class has any virtual functions, it should have a virtual destructor. Classes not designed to be base classes or not designed to be used polymorphiccally should not declare virtual destructors. 4/13/2012 Version 2.00

65 Example without a Virtual DestructorThe output of running the code would be: #include iostream.h class Base { public: Base(){ cout<<"Constructing Base";} // this is a destructor: ~Base(){ cout<<"Destroying Base";} }; class Derive: public Base Derive(){ cout<<"Constructing Derive";} ~Derive(){ cout<<"Destroying Derive";} void main() Base *basePtr = new Derive(); delete basePtr; } Constructing Base Constructing Derive Destroying Base Problem: Based on the output above, we can see that the constructors get called in the appropriate order when we create the Derive class object pointer in the main function. However, the destructor for the "Derive" class does not get called at all when we delete ‘basePtr’. Solution: we have to make the base class destructor virtual so that the destructor for any derived class will be called. 4/13/2012 Version 2.00

66 Virtual Destructor ExampleSo, the only thing we will need to change is the destructor in the Base class and here’s what it will look like: The output of running the code above would be: #include iostream.h class Base { public: Base(){ cout<<"Constructing Base";} // this is a virtual destructor: virtual ~Base(){ cout<<"Destroying Base";} }; class Derive: public Base Derive(){ cout<<"Constructing Derive";} ~Derive(){ cout<<"Destroying Derive";} void main() Base *basePtr = new Derive(); delete basePtr; } Constructing Base Constructing Derive Destroying Derive Destroying Base 4/13/2012 Version 2.00

67 Friend Classes[Seldom used]You can allows all the function members of one class to have access to all the data members of another by declaring it as a friend class. It is critical to understand that when one class is a friend of another, it only has access to names defined within other class. It does not inherit the other class. Specifically, the members of the first class do not become members of the friend class. Friend classes are seldom used. They are supported to allows certain special case situations to be handled. 4/13/2012 Version 2.00

68 Private Inheritance Advantage DisadvantageIt allows the derived class to access the protected member functions of the base class. It allows the derived class to override the virtual functions of the base class. Using private inheritance causing the code to become less flexible and error-prone in a multiple programmer scenario. Inheritance requires the presence of a v-table and creates unnecessary performance issue. 4/13/2012 Version 2.00

69 Derived class can access the protected member of private base class.// Demonstration of Private Inheritance #include using namespace std; class ElectricMotor { public: ElectricMotor () {}; virtual ~ElectricMotor () {}; void StartMotor() Accelerate (); Cruise(); } void StopMotor() speed = 0; cout << "Motor stopped at speed = " << speed << endl; private: void Accelerate () speed = speed + 50; cout << "Motor started speed = " << speed << endl; void Cruise() cout << "Motor running at constant speed = " << speed << endl; // Protected specifier allows the private inheritance derived class Fan to // access protected item. If speed is set to private specifier, compiler // error is found in derived Fan class for accessing private item speed. protected: int speed; }; class Fan : private ElectricMotor { public: Fan () { speed = 0; }; ~Fan() { speed = 0; }; void StartFan () { StartMotor(); } void StopFan () { StopMotor(); } }; int main() Fan mFan; mFan.StartFan(); mFan.StopFan(); /* Note: the next two lines access the base class ElectricMotor. However, * as Fan features 'private inheritance' from ElectricMotor, neither the base class * instance nor its public methods are accessible to the the user of class Fan. * Un-comment them to see a compile failure. */ //mFan.Accelerate(); //ElectricMotor *pMotor = &mFan; } 4/13/2012 Version 2.00