| 1. What is a pointer? Name one advantage to having pointers as part of C++. How do you declare a pointer? |
A pointer is a variable that stores the memory address of another variable. Advantages: (1) Dynamic memory allocation, (2) Efficient passing of large objects by reference, (3) Enables polymorphism through inheritance, (4) Allows building complex data structures. Declaration: int* ptr; or int *ptr; (the position of the * is flexible) |
| 2. Explain what the * and & characters do when dealing with pointers. (* is used in two different ways.) |
The & operator is the address-of operator; it returns the memory address of a variable (e.g., &x gets the address of x). The * operator is used in two ways: (1) In declaration, it denotes a pointer type (int* ptr declares ptr as a pointer to int), (2) As a dereference operator, it accesses the value at the address the pointer points to (e.g., *ptr retrieves the value at that address). |
| 3. Why should we always initialize a pointer to nullptr? |
Uninitialized pointers contain garbage values (random memory addresses), leading to undefined behavior if dereferenced. Initializing to nullptr prevents random memory access. It also allows safe checking (if (ptr != nullptr)) to verify whether a pointer is valid before use, preventing crashes from dereferencing invalid addresses. |
| 4. See the picture in slide 8 & 9 in the generic pointer slides. Be able to explain what is happening in memory like in those slides. |
The slides show pointer memory diagrams: (1) A pointer variable holds a memory address, shown as boxes at different memory locations. (2) The & operator gets the address of a variable (e.g., p = &num makes p store the address 1800 where num is located). (3) The * operator dereferences a pointer to access the value at that address (e.g., *p = 24 stores 24 at the location p points to, changing num's value). (4) Each variable occupies a memory location with an address, and pointers allow indirect access to those locations. |
| 5. What is a dynamic array? What is special about dynamic memory? |
A dynamic array is allocated at runtime on the heap using new: int* arr = new int[10];. Special characteristics: (1) Size can be determined at runtime, (2) Lives on the heap (not limited by stack size), (3) Lifetime extends until explicitly deleted, (4) Must be manually deallocated with delete[], (5) Allows for more flexible memory management than static arrays. |
| 6. What does this do: *(arr+i)? What can I use instead? |
*(arr+i) accesses the element at index i in an array using pointer arithmetic. It dereferences the pointer (arr+i), returning the value at that memory location. Alternative: arr[i] is equivalent and more readable. Both perform the same operation - accessing the i-th element of the array. |
| 7. What is the benefit of passing a pointer to a function? Can you return a pointer from a function? |
Benefits of passing pointers: (1) Avoids copying large objects, improving efficiency, (2) Allows the function to modify the original variable (pass by reference), (3) Pointers can be null, allowing optional parameters. Yes, you can return a pointer, but be cautious: avoid returning pointers to local variables (dangling pointer). Return pointers to dynamically allocated memory or to objects that exist beyond the function's scope. |
| 8. When do we use ->? |
The -> operator is used to access members of an object through a pointer. Syntax: pointer->member is equivalent to (*pointer).member. Example: if ptr points to an object of class Dog with a member age, you use ptr->age to access it. |
| 9. When are destructors called (two different ways)? |
Destructors are called in two ways: (1) When an automatically allocated object (on the stack) goes out of scope, the destructor is called automatically. (2) When a dynamically allocated object (on the heap) is explicitly deleted using the delete operator, the destructor is called. |
| 10. What is the difference between shallow and deep copies of arrays? How do you implement them? |
Shallow copy: Only copies the pointer value; both objects point to the same memory. Causes issues if one object deletes the memory. Deep copy: Allocates new memory and copies the actual data. Implementation: Define a copy constructor and an assignment operator (operator=) that allocate new memory and copy the data member-by-member. The destructor should also be defined to properly deallocate memory. |
| 11. If a class has a pointer data member, what two functions must be defined for it and why? |
The two functions that must be defined are: (1) Copy constructor: to create a proper deep copy when an object is copied, and (2) Assignment operator (operator=): to perform deep copy assignment. These are necessary because the default versions only do shallow copies, which leads to double-deletion and memory errors when objects are destroyed. |
| 12. What are the 3 instances when a copy constructor gets called? |
The copy constructor is called in three instances: (1) When passing an object by value to a function, (2) When returning an object by value from a function, (3) When initializing a new object with an existing object of the same class (e.g., MyClass obj2 = obj1;). |
| 13. Class B inherits from Class A. Can you assign an object of Class A to Class B? Can you assign an object of class B to class A? |
Assign Class A to Class B: No, because B is a derived class (more specific) than A. A pointer or reference to B cannot be initialized with an A object. Assign Class B to Class A: Yes (through a base class pointer or reference), because B is-a A. A base class can reference a derived class object, though information specific to B is lost if stored in an A object. |
| 14. What is the difference between dynamic(run time) and static(compile time) binding? How does defining a function as virtual contribute to the binding? |
Static binding (compile-time): The function to be called is determined at compile time based on the declared type. Dynamic binding (runtime): The function to be called is determined at runtime based on the actual object type. Defining a function as virtual enables dynamic binding. Without virtual, derived class functions are statically bound and won't be called through a base class pointer; with virtual, the actual object's version is called. |
| 15. Be able to explain what is happening in slide 8 of Chapter 12 part 3 - which print is getting called and why? What would happen if pet and dog were objects instead of pointers? |
When pet and dog are objects (not pointers): pet = dog; causes type slicing. The dogType object is converted to a petType object, and any derived class data members (like breed) are lost. You can only access base class members through pet. If you try to call a function only available in the derived class (like pet.setBreed()), you get a compile-time error. With pointers, pet would point to the actual dogType object, and virtual functions would dynamically bind to the correct derived class version at runtime. |
| 16. How does dynamic binding contribute to polymorphism? |
Dynamic binding enables polymorphism by allowing the same function call to behave differently depending on the actual object type at runtime. Through base class pointers/references, you can call virtual functions on derived class objects, and the correct derived class version is executed. This allows writing generic code that works with multiple derived classes without knowing their specific types at compile time. |
| 17. How should having a virtual function affect the destructor? Why? |
If a class has virtual functions, its destructor should also be virtual. This ensures that when a derived class object is deleted through a base class pointer, the derived class destructor is called first (via dynamic binding), properly cleaning up derived class resources before the base class destructor is called. Without a virtual destructor, only the base class destructor runs, leaving derived class resources uncleared. |
| 18. What is a pure virtual function? How do we make a function "pure virtual"? What is the effect on a class with a pure virtual function? |
A pure virtual function is a virtual function with no implementation in the base class, serving as an interface that derived classes must implement. Syntax: virtual void functionName() = 0; The =0 denotes a pure virtual function. Effect: A class containing one or more pure virtual functions becomes an abstract class and cannot be instantiated. Derived classes must provide implementations for all pure virtual functions to be concrete classes. |