Programmare a oggetti un televisore in C++

Questo articolo potrebbe avere come titolo: Introduzione alla programmazione a oggetti; infatti il post vuole rispondere alle domande seguenti:

  • Come si imposta un programma a oggetti ?
  • Quali elementi inserire nella classe che rappresenta l’oggetto?

In questo articolo svilupperemo un programma che simula il funzionamento di un televisore allo scopo di mostrare a piccoli passi quali sono i componenti principali di un programma a oggetti senza l’ereditarietà.

Chi volesse già guardare o copiare il codice per provarlo può scendere alla fine dell’articolo andando qui.

Descrizione funzionalità del programma televisore

Il programma che andremo a sviluppare vuole simulare un televisore che:

  • abbia le funzionalità standard principali di un telecomando tipo: accendi, spegni, cambia canale, cambia luminosità
  • permetta il “parental Control” tramite il blocco di canali indesiderati
  • sia pensato per essere posizionato in una particolare stanza tipo: salotto, cucina, stanza dei bambini; questo allo scopo di aggiungere, magari successivamente, la possibilità di adattare il parental control in base alla stanza dove è collocato (o anche l’elenco dei canali preferiti più adatti a quella stanza o alle ore della giornata in cui sto lì)

Componenti di un programma a oggetti

Se conosciamo le basi della programmazione a oggetti sappiamo che una classe (che è la rappresentazione dell’oggetto) dovrebbe avere al suo interno le seguenti cose:

  1. variabili o attributi che possono essere:
    statici:
    e cioè quelli che rappresentano le caratteristiche dell’oggetto che non cambiano nel tempo; nel nostro esempio:
    ...
    private:
      string marca;
      int nPollici;//numero di pollici 
    ...
    dinamici dette anche variabili di stato:
    e cioè quelli che rappresentano le variazioni dello stato interno dell’oggetto; nel nostro esempio:
    ...
    private:
      bool accesa;//true: la televisione è accesa, false spenta
      int volume;
      int luminosita;
      int canaleAttuale;
      string stanza;
      
      bool parentalControlAttivo;//true attivo, false: non attivo
      int canaliBloccati[MAXCANALIBLOCCABILI];
      int numCanaliBloccati;  
    ...
  2. i metodi che possono essere
    metodi costruttori:
    che sono quelli che vengono chiamati in automatico all’atto dell’istanziazione (ovvero della creazione) dell’oggetto; abbiamo fatto solo tre che riteniamo necessari, ma se ne potrebbero fare altri.
    ...
    public:
      //costruttori
      televisione();
      televisione(string room);
      televisione(string room, int pollici);
      televisione(string room, string m, int pollici);
    ...
    il metodo distruttore
    che viene chiamato in automatico quando l’oggetto cessa di esistere (nel nostro caso il distruttore non farà nulla)
    ...
      //distruttore
      ~televisione();
    ...
    tutti gli altri metodi che:
    • rappresentano azioni, invio o ricezione di messaggi (nel nostro esempio accendi, spegni e altro
      ...
        //azioni del telecomando
        void accendi();
        void spegni();    
        //controlli e visualizzazioni
        void addBloccoCanale(int c);
      ...
    • oppure servono a settare (setter) o leggere i valori (getter) degli attributi (nel nostro caso, ad esempio: setCanale che serve a impostare il canale premendo sul telecomando)
      ...
        //azioni del telecomando
        void setCanale(int c);//i canali vanno da 0 a CANALEMAX
        void setLuminosita(int l);
        void changeCanale(bool su);//su=true aumenta di uno, false diminuisce
        void changeLuminosita(bool su);//su=true aumenta di uno, false diminuisce
        void setParentalControl(bool pc);//true = attiva, false=disattiva
        //controlli e visualizzazioni
        bool isAccesa();
        void visualizzaStato();
        void getCanaliBloccati();
      ...

Alla chiusura della classe inseriamo il main composto da un menù di scelta tramite un costrutto “switch-case” inserito poi in un ciclo e, subito dopo il main, le implementazioni dei metodi.

Codice sorgente televisore in C++

Ecco il codice sorgente completo che potete anche provare su Ideone dove sono stati dati i seguenti Input:
11 1 11 3 11 13 (11 visualizza lo stato, 1 accende, 3 cambia canale, 13 esce)

#include <iostream>
#include <stdlib.h>
#define MAXCANALIBLOCCABILI 50
#define MAXCANALE 889  
#define MAXLUMINOSITA 100
using namespace std;

class televisione
{
private:
  bool accesa;
  string marca;
  int nPollici;
  int volume;
  int luminosita;
  int canaleAttuale;
  string stanza;
  
  bool parentalControlAttivo;//true attivo, false: non attivo
  int canaliBloccati[MAXCANALIBLOCCABILI];
  int numCanaliBloccati;  

  bool isBloccato(int c);//dice se il canale c è nell'elenco dei bloccati

public:
  //costruttori
  televisione();
  televisione(string room);
  televisione(string room, int pollici);
  televisione(string room, string m, int pollici);
  //distruttore
  ~televisione();
  //azioni del telecomando
  void accendi();
  void spegni();    
  void setCanale(int c);//i canali vanno da 0 a CANALEMAX
  void setLuminosita(int l);
  void changeCanale(bool su);//su=true aumenta di uno, false diminuisce
  void changeLuminosita(bool su);//su=true aumenta di uno, false diminuisce
  void setParentalControl(bool pc);//true = attiva, false=disattiva
  //controlli e visualizzazioni
  bool isAccesa();
  void visualizzaStato();
  void addBloccoCanale(int c);
  void getCanaliBloccati();
};

//costruttori
televisione::televisione()
{
  stanza="salotto";
  marca = "LG";
  nPollici=22;
  accesa=false;
  volume=20;
  luminosita=50;
  canaleAttuale=1;
  parentalControlAttivo=false;
  for(int i=0; i<MAXCANALIBLOCCABILI;i++) 
    canaliBloccati[i]=0;
  numCanaliBloccati=0; 
}

televisione::televisione(string room)
{
  stanza=room;
  nPollici=24;
  marca = "LG";
  accesa=false;
  volume=20;
  luminosita=50;
  canaleAttuale=1;
  parentalControlAttivo=false;
  for(int i=0; i<MAXCANALIBLOCCABILI;i++) 
    canaliBloccati[i]=0;
  numCanaliBloccati=0;
}

televisione::televisione(string room, int pollici)
{
  stanza=room;
  nPollici=pollici;
  marca = "LG";
  accesa=false;
  volume=20;
  luminosita=50;
  canaleAttuale=1;
  parentalControlAttivo=false;
  for(int i=0; i<MAXCANALIBLOCCABILI;i++) 
    canaliBloccati[i]=0;
  numCanaliBloccati=0;
}
televisione::televisione(string room, string m, int pollici)
{
  stanza = room;
  marca = m;
  nPollici = pollici;
  accesa = false;
  volume = 20;
  luminosita = 50;
  canaleAttuale = 1;
  parentalControlAttivo = false;
  for(int i=0; i<MAXCANALIBLOCCABILI;i++) 
    canaliBloccati[i]=0;
  numCanaliBloccati=0; 
}
//implementazione del distruttore
televisione::~televisione(){}
//implementazione azioni del telecomando
void televisione::accendi(){  accesa = true; }
void televisione::spegni(){  accesa = false; }
void televisione::setCanale(int c)
{
  if( (parentalControlAttivo == true)  and (isBloccato(c)) ) return;
  if((c>=0) and (c<=MAXCANALE))
    canaleAttuale = c;
  //altrimenti il canaleAttuale resta quello di prima
}
void televisione::setLuminosita(int l)
{
  if((l>=0) and (l<MAXLUMINOSITA))
    luminosita = l;
}
/*
void televisione::changeCanale(bool su)
{
  if(su == true) canaleAttuale++;
  else canaleAttuale--;

  //qui ho settato il canaleAttuale ma potrebbe essere bloccato
  if(parentalControlAttivo == true)
    if(isBloccato(canaleAttuale) )  changeCanale(true);
  //funzione ricorsiva cioè una funzione che richiama se stessa
}
*/
//versione con controllo errori:
void televisione::changeCanale(bool su)
{
  if(su) canaleAttuale =  (canaleAttuale+1) % (MAXCANALE+1) ;
  else canaleAttuale--;
  
  if(canaleAttuale == 0 ) 
    if(su) canaleAttuale++;
    else canaleAttuale = MAXCANALE;

  //qui ho il canaleAttuale ma potrebbe essere bloccato
  if(parentalControlAttivo == true)
    if(isBloccato(canaleAttuale) )  changeCanale(true);
  //funzione ricorsiva cioè una funzione che richiama se stessa
}

void televisione::changeLuminosita(bool su)
{
  if(su) luminosita++; else luminosita--;  
}
//versione con controllo degli errori
//si fa come quella di changeCanale
void televisione::setParentalControl(bool pc)
{
  parentalControlAttivo = true;
}
  //controlli 
bool televisione::isAccesa(){ return accesa; }
void televisione::visualizzaStato()
{
  if( accesa == false ) 
    {
      cout<<"ATTENZIONE: accendere il televisore"<<endl;
      return;
    } 
  cout<<"televisore: "<<marca<<" "<<nPollici<<" pollici"<<endl;
  cout<<"canale: "<<canaleAttuale<<endl;
  //eccetera  
}

void televisione::addBloccoCanale(int c)
{
  if(isBloccato(c)) return;
  if((c>=0) and (c<MAXCANALE))
  {
    canaliBloccati[numCanaliBloccati] = c;
    numCanaliBloccati++;
  }
  return; 
}
bool televisione::isBloccato(int c)
{
  for(int i=0; i<MAXCANALE; i++)
    if(canaliBloccati[i] == c) return true;
  return false;
}
void televisione::getCanaliBloccati()
{
  cout<<"CANALI BLOCCATI: "<<endl;
  for(int i=0; i<numCanaliBloccati ;i++)
    cout<<canaliBloccati[i]<<" ";
  cout<<endl;

}

int main() {
    televisione a("bambini");
    int scelta;

    do{
      cout<<"scegli:"<<endl;
      cout<<"0: spegni"<<endl;
      cout<<"1: accendi"<<endl;
      cout<<"2: cambia canale"<<endl;
      cout<<"3: aumenta canale"<<endl;
      cout<<"4: diminuisci canale"<<endl;
      cout<<"5: cambia luminosita'"<<endl;
      cout<<"6: aumenta luminosita'"<<endl;
      system("pause");
      cout<<"7: diminuisci luminosita'"<<endl;
      cout<<"8: attiva il controllo parentale'"<<endl;
      cout<<"9: disattiva il controllo parentale'"<<endl;
      cout<<"10: blocca canale"<<endl;
      cout<<"11: visualizzaStato"<<endl;
      cout<<"12: dammi l'elenco dei canali bloccati"<<endl;
      cout<<"13: esci dal programma"<<endl;
      cin>>scelta;
      switch(scelta)
      {
        case 0: 
	  a.spegni();
	  break;
        case 1: 
	  a.accendi();
	  break;
        case 2: 
	  int c;
	  cout<<"dammi il canale: ";
	  cin>>c;
	  a.setCanale(c);
	  break;
        case 3: 
	  a.changeCanale(true);
	  break;
        case 4: 
	  a.changeCanale(false);
	  break;
        case 5: 
	  int l;
	  cout<<"dammi la luminosita: ";
	  cin>>l;
	  a.setLuminosita(l);
	  break;
        case 6: 
	  a.changeLuminosita(true);
	  break;
        case 7: 
	  a.changeLuminosita(false);
	  break;
        case 8: 
	  a.setParentalControl(true);
	  break;
        case 9: 
	  a.setParentalControl(false);
	  break;
        case 10: 
	  cout<<"dammi il canale da bloccare: ";
	  cin>>c;
	  a.addBloccoCanale(c);
	  break;
        case 11:
	  a.visualizzaStato();
	  break;
        case 12:
	  a.getCanaliBloccati();
	  break;
        case 13: 
	  cout<<"bye bye!!!"<<endl; break;
	  break;
        default: 
	  cout<<"scelta errata!!!"<<endl;
	  system("PAUSE");
      }
    } while(scelta != 13);

return 0;
}

La versione successiva di questo programma prevederà l’uso dell’ereditarietà.
Per adesso buon divertimento e fatene buon uso ;)!!!