Contenuti del Corso
OOP in C++
OOP in C++
Metodo Virtuale Puro
Il concetto di metodi virtuali è fondamentale per ottenere il polimorfismo, consentendo un design software flessibile ed estensibile. I metodi virtuali puri ampliano questo concetto definendo interfacce e supportando il binding dinamico.
Sintassi del metodo virtuale puro
Un metodo virtuale puro viene dichiarato con la parola chiave virtual
e inizializzato a zero. Indica che la funzione non ha una definizione all'interno della class
e deve essere sovrascritta da qualsiasi sottoclasse prima che possano essere istanziati oggetti di quella class
.
virtual.h
virtual void example() = 0;
Questo metodo funziona in modo simile a uno standard, tranne per il fatto che non ha un corpo racchiuso tra { }
ed è invece terminato con = 0;
, indicando l'assenza di implementazione. Tuttavia, le altre regole per questo metodo sono le stesse dei metodi regolari.
Dichiarare un metodo virtuale puro rende la class
in cui è dichiarato astratta, il che significa che diventa impossibile istanziare oggetti di quella classe. Questa restrizione esiste perché ogni metodo all'interno della class
deve essere implementato prima di creare e utilizzare un'istanza, al fine di prevenire errori e comportamenti imprevedibili. Osserva il codice qui sotto:
Animal.h
class Animal { public: virtual void speak() = 0; };
La Animal
class
presenta un metodo virtuale puro chiamato speak()
, impedendo l'istanza di oggetti da questa classe. Questa progettazione è sensata, poiché lo scopo del metodo virtuale è rappresentare i suoni distintivi che ogni animale emette.
Rendendo il metodo virtuale, si consente a ogni sottoclasse di implementare la propria versione, cogliendo l'individualità del suono di ciascun animale. Dichiararlo come virtuale puro indica che non esiste un'implementazione predefinita, sottolineando la necessità di implementazioni concrete nelle classi derivate.
main.cpp
#include "Animal.h" int main() { // cannot declare variable 'animal' to be of abstract type Animal animal; }
Anche questo è logico. Creare istanze della Animal
class
sarebbe impraticabile e controintuitivo, poiché rappresenta un concetto astratto che funge da categoria per vari animali. Non esiste un comportamento specifico associato a un animale generico, rafforzando la natura astratta della class
e sottolineando l'importanza di creare sottoclassi specializzate per rappresentare i suoni unici di ciascun animale specifico.
main.cpp
#include <iostream> class Animal { public: // Pure virtual function to enforce implementation in derived classes virtual void speak() = 0; }; class Cat : public Animal { public: void speak() override { std::cout << "Meow!" << std::endl; } }; class Dog : public Animal { public: void speak() override { std::cout << "Bark!" << std::endl; } }; class Cow : public Animal { public: void speak() override { std::cout << "Moo!" << std::endl; } }; void pet(Animal& animal) { animal.speak(); } int main() { // Replace `Cat` with `Dog` or `Cow` to see their specific behavior Cat cat; pet(cat); }
Anche se non è possibile creare un oggetto di tipo Animal
direttamente, è comunque possibile utilizzarlo come parametro in una funzione. Analogamente all'esempio precedente del pulsante, questo approccio sfrutta il polimorfismo per realizzare un programma versatile che può modificare dinamicamente il proprio comportamento durante l'esecuzione.
Prova a passare un oggetto di una diversa class
alla funzione e osserva l'output. Inoltre, tenta di creare un oggetto della class
astratta per vedere come il compilatore impedisce l'istanza a causa dei metodi puri virtuali non implementati.
Grazie per i tuoi commenti!