0:04
In this episode, we continue our case study
on watches -- Swiss made or not --
and we will attack the polymorphic output
of the various products in our hierarchy.
As a reminder, in the last step,
we had drafted a product hierarchy
and we will now focus on
how to make sure that these different products
can be displayed in a polymorphic way.
Basically, a product like a watch, a mechanism
or an accessory will have its own way of being displayed
and we want this display to be polymorphic.
Meaning that if we put an object
of type Montre, for example, in a variable of type Produit
and we call the output method on that variable,
the the output should automatically adapt to the actual type of the instance stored
in the variable. So each product will have its own way
of being displayed, and we want to know how to procede
to implement a polymorphic output
We would like this output
to be made using the output operator.
So concretely here if we imagine, for example,
that we declare
a pointer <i>p</i> to a product
[Silence]
1:13
we would like this, "display the contents pointed to by <i>p</i>"...
to display the information specific to the watch.
So, is it possible to program
this operator to have the desired polymorphic behavior?
The answer is yes.
Of course, it is not the operator itself which will be declared
as a virtual method.
It is not a method. It is a function
that is external to all classes,
so the operator itself cannot be virtual.
However, nothing prevents us from invoking a virtual, polymorphic method
on the operand it must display.
So the idea here is to make our output operator
call a polymorphic method
which would be defined at the superclass level.
In this case, in the <i>Produit</i> superclass.
Our operator allowing the output of a product
will thus call an <i>afficher</i> method (TN: "afficher" means "display")
defined in the <i>Produit</i> superclass;
of course, this <i>afficher</i> method must be declared as virtual
to allow polymorphic behavior
Remember that here, it is the fact that this method is virtual
and that it is called via a reference to a product
that allows it to have a polymorphic behavior, as desired.
You will notice that the <i>afficher</i> method is defined as public
first, because it makes sense to
offer this functionality
to the outside world,
but also because it will free us
from some constraints
related to programming the output operator.
Typically here, since <i>afficher</i> is a public-accessible method,
the operator can be programmed to use it directly
and so, it isn't necessary to use <i>friend</i>
to access this method of the <i>Produit</i> class.
Once a method, in a class,
is declared as virtual,
it means that we can potentially use instances
of this class in a polymorphic way.
And so, we must think about destroying them appropriately
by introducing a destructor, which will be virtual
We want want the output method of a product
to display its price by default.
We could imagine writing the <i>afficher</i> method
in such a way that it displays the price of a product.
This solution, however, is not good.
Do you know why?
Indeed, the price of a subclass of Produit could very well be different
from the base value
Using the base value to display the price
will thus not be correct for all the possible instances of Produit
including its subclasses.
Indeed, for subclasses of Produit such as bracelets, for example,
we could perfectly imagine that the price
would correspond to the base value of the product;
however, for watches, another type of product,
we could imagine that the calculation of the price would be more complex
and that it would be the sum of the prices of all its components.
The correct way to proceed here
is therefore to use, instead of values,
the prix() (means "price()") method, which will itself of course
be capable of having a polymorphic behavior and calculate the price of a watch
if the displayed product is a watch, or the price of a bracelet
if we are displaying a bracelet.
If we go back to our initial example,
the one where we declared a pointer on a product in which we stored
the address of a watch,
imagine now that we call the output operator
on the object pointed to by <i>p</i>.
What happens here?
This will be translated by a call to the output operator,
that we have overloaded for products.
4:50
It will call the <i>afficher</i> method,
knowing that now, this variable, this parameter,
contains a reference to a watch.
The <i>afficher</i> method, as it is defined in the Produit class,
will be called,
and it will itself call the price calculation method, <i>prix()</i>.
This method is polymorphic, so it will automatically adapt
to the real nature of the object on which it is called,
which it so happens is a watch here.
The <i>prix()</i> method is indeed virtual.
As we allow it to access the real instance
through a pointer,
it can truly apply in a polymorphic way
and we will have the desired result.
That is, the price for a watch will be calculated as, for example,
the sum of the prices of all its components.
Now, let's finalize our Produit class.
Suppose that we wish to impose the fact that
the base value of a product should remain unchanged once we initialized it.
That way, a product's base value would remain as
it was initialized, and it would be impossible to change it
during the lifetime of the product.
This can be forced by labeling the variable as constant.
We will be able to initialize the <i>valeur</i> member variable, but once this is done,
we will no longer be able to change its value
If we also wish to impose
that by default, a product has a base value of zero,
we can do this by using a default value
for the constructor's parameter.
So we would have
a default constructor for the <i>Produit</i> class
which, when called,
would initialize the product's value with a value of <i>0</i>.
Finally, let's imagine that we want to model
the fact that a product does not exist as such,
that it is an abstract entity in our design
and that we cannot create any instance of Produit as such.
How do we force this constraint in our design?
In C++, for a class to be abstract,
it must contain at least one pure virtual method,
meaning that here, we would need to have a method
6:41
defined as pure virtual.
We don't really have any reason to create one here,
and creating one artificially would not really make any sense.
A good candidate for a pure virtual method
in a class is actually the destructor.
The destructor can be declared as pure virtual to ensure that
the class becomes abstract.
Since any class necessarily has a destructor,
the fact of declaring it as pure virtual
saves us from having to create an artificial method
simply to make the class abstract
Note that it is imperative to give a body to all destructors
and note, at the same time, that nothing prevents a pure virtual method
from having a body.
This syntax, however, is not valid C++
so it is not possible to specify the body of a pure virtual destructor
within the class, like so.
We will have to define the destructor of
the Produit class outside of the class, with this syntax.
Meaning that within the <i>Produit</i> class,
we declare the destructor as pure virtual,
and we define its body outside.
So this body must be specified,
we must give a definition for the destructor even if it doesn't do anything.
This is what we obtain, after this step,
for the code of the Produit class.
The constructor of the class allows initialization
of its <i>valeur</i> attribute using a value passed as parameter.
This constructor can be used as a default constructor
since all of its parameters have a default value,
a value of <i>0</i> here.
The <i>Produit</i> class provides an output method
that can be used in a polymorphic way.
This method is declared as virtual,
so if it is used via a pointer or a reference,
then it will exhibit polymorphic behavior.
It then calls another potentially polymorphic method,
the <i>prix()</i> method, also declared as virtual
The output operator can be overloaded
to display instances of <i>Produit</i>.
In order to have polymorphic behavior,
it simply has to call a polymorphic output method in its body; a method
defined as public in the <i>Produit</i> class.
Finally, to model the fact that a product
is an abstract entity in our design,
we have declared the destructor as pure virtual
and we did not forget to define it
even if we have nothing specific to make it do, here.
And this concludes our episode on the definition of products
and their polymorphic output.