Module 04 - Marymota/CPP_Modules GitHub Wiki
Ex00
Instance
In a computer system, any time a new context is created based on some model, it is said that the model has been instantiated. In practice, this instance usually has a data structure in common with other instances, but the values stored in the instances are separate.
Const classes
Instantiated class objects can be made constant by using the 'const' keyword. All const variables must be initialized at time of creation. In the case of const class objects, initialization is done via class constructors. const Animal* meta = new Animal(); Once a const class object has been initialized via constructor, any attempt to modify the member variables of the object is disallowed. This includes both changing member variables directly (if they are public), or calling member functions that set the value of member variables.
'New' keyword: Objects created on the stack have a name and don't need a pointer to be accessed. The objects created with the 'new' keyword are allocated on the heap, don't have a name, and need a pointer so that it can be referenced and to access its member variables and functions. When 'new' is used to allocate memory for a c++ class object, the object's constructor is called after the memory is allocated. The 'delete' operator must be used to deallocate the memory allocated by the 'new' operator. The 'delete[]' operator is used to delete an array allocated by the 'new' operator.
Virtual functions and polymorphism
A virtual function is a member function in the base class define with the virtual keyword. It is expected to be overriden in derived classes. Without the virtual keyword, the call to the member function is set once by the compiler as the version defined by the Parent class. This is known as static resolution, static linkage or early binding. (The arrow operator (->) is used to access member functions through a pointer.) By declaring the member function of the Parent as virtual, the function will allways be overriden. This is even though the pointer of type Parent. But it holds the address of the Child. The virtual keyword tells the compiller that we don't want early binding for the given function. We'll use late binding or dynamic linkage.
Resources:
Instance - word definition
Const class objects and member functions
Define classes and create objects in C++
new operator (c++)
C++ OOP - Virtual Functions
Ex01
Virtual Destructor
Deleting a derived class object using a pointer of base class type that has a non-virtual destructor results in undefined behaviour. To correct this situation, the base class should be defined with a virtual destructor. Making base class destructor virtual guarantees that the object of derived class is destructed properly, i.e., both base class and derived class destructors are called.
In the WrongAnimal class where a virtual function and virtual destructor is not implemented, WrongCat makes the same noise as the base class when called by a WrongCat object, and also, the WrongCat destructor is never called.
Difference between Shallow and Deep copy of a class
A shallow copy works well when the classes do not contain any dynamically allocated memory. However, because shallow copies of a pointer just copy the address of the pointer, it does not allocate any memory or copy the contents being pointed to. When a destructor is called on the copy, and consequently, the destructor also deletes the dynamically allocated memory that both base object and copy object are pointing too. If this happens base object will be left pointing to an invalid block of memory.
A Deep copy will allocate memory for the copy and then copies the actual value, so that the copy lives in distinct memory from the source. This way, the copy and source are distinct and will not affect each other in any way.
Shallow Copy: Stores the references of objects to the original memory address Deep Copy: Deep copy stores copies of the object's value. Shallow Copy: Reflects changes made to the new/copied object in the original object. Deep Copy: Doesn't reflect changes made to the new/copied object in the original object. Shallow Copy: Stores the copy of the original object and points the references to the objects. Deep Copy: Stores the copy of the original object and recursively copies the objects as well. Shallow Copy: Faster Deep Copy: Slower
To create a Deep copy of an object Dog/Cat, the copy constructor will need to create a new Brain that receives as parameter the contents of the original Brain.
_brain = new Brain(*copy._brain);
In the example above, both _brains, the original and the copy, would contain a pointer do the same "brain". If the original was to be changed the one in the copy also would be changed. Also, if the copy was deleted, the original would be stuck pointing to an invalid piece of memory.
If we are copying the contents of one object to another that was already created, the copy assignment operator will be called instead. Here we already have a formed brain by the initial constructor that created the object, so we just need to copy the contents of one Brain to the copy Brain. Again, to avoid a shallow copy, instead of using: _brain = other._Brain
we use: *_brain = *other._brain
so that the contents will be replicated instead of just the pointer itself.
Resources:
Virtual Destructor
Difference between Shallow and Deep copy of a class
14.16-Shallow vs. deep copying
C at work, copy constructors assignment operators and more
Copy constructors, assignment operators, and exception safe assignment
Ex03
Circular Dependency and Forward Declaration
Circular dependency happens when one or more modules are related to each other either directly or indirectly. In the case of this exercise, AMateria has a method that is dependent on the ICharacter class virtual void use(ICharacter& target):
, while ICharacter has a method that it's dependent on the AMateria class virtual void equip(AMateria* m) const = 0
.
When compiling there will be an error stating that the necessary class has not been declared, even when including it. To solve this it is necessary to state that the class we are using exists by adding it to the header file:
In ICharacter.hpp we add class AMateria;
.
In the
This is called a forward declaration.
Resources:
Circular dependency | Forward Declaration | #pragma once | C++