It's time for the summary.
If we want to access the objects data member through a pointer,
we need to first dereference that pointer to use the dot
operator, because dot operator cannot be used on the pointer
itself. But there is a cleaner way to do this.
We can instead use the member of pointer operator,
also known as the arrow operator.
Arrow operator will dereference the pointer and then access the objects member.
We also discussed runtime polymorphism when working with class
inheritance. Pointer to the base class can be used as an interface
for derived classes, but since we are pointing to the derived class
with the base class pointer,
we can only access the member functions that belong to the base class.
However, we can fix this by late binding the overridden functions at runtime.
All we need to do is make the member function from the base class virtual.
And now, every derived class will have an additional virtual
pointer inherited from the base class.
This virtual pointer points to the virtual table, which
helps the compiler bind the correct function to the
correct type of object at runtime.
Whenever you work with virtual functions,
you also need to make the destructor virtual to prevent potential
memory leaks. When the resource is too large,
we need to allocate it on the heap.
This forces us to use pointers as data members to point to these
allocated resources, and that is where the concept of RAII comes
in. We need to take care of those resources once the object goes
out of scope. To do this,
we can use the delete operator inside of the class's
destructor to deallocate resources from the heap.
However,
if we try to assign one object instantiated from this class to another
one, things get complicated. Copy assignment operator and copy
constructor make shallow copies, which means that they only copy the
pointer's address but not the resource itself.
We need to redefine these copy semantics to allocate new resources.
We need to make a deep copy instead of a shallow one.
But sometimes, deep copies are just an overkill, because we are
working with temporary values. To improve performance, we can
implement move semantics, which will steal the resources from
another object instead of making a copy.
Move constructor and move assignment operator will also invalidate
the object that was relinquished of its resources.
We can use rvalue references to overload the copy
constructor, and then all of the temporary values will be
sent to the move constructor instead.
Prvalue is the value category that represents temporary values
without an identity, like integer literals, for example. Lvalue
is the value that has an identity.
This can be a variable,
a pointer, a reference, or anything else that has a fixed place in memory.
We can use std::move function to return an rvalue
reference to the functions argument.
This will turn that value into an xvalue, expired value that has an
identity but it is also movable. Glvalue is a super category that
represents values with an identity, and lvalue belongs to the glvalue
category. Rvalues are movable values, so prvalues are also rvalues,
but xvalues are both rvalues and glvalues, because they are movable and they
can have an identity. And, we are done with this module.
If you have any questions,
ask them in the discussion. I will see you in the next one,
where we will go over modern C++ ways of handling all of the
things we covered until now.
Thank you for watching.