sabato 30 agosto 2014

Una funzione della classe che modifica il form, che disegna una griglia di labels sul form.

    class Modificatore
    {

        public static void disegnaGriglia(Form Frm,int numero,int colonne)
        {
            Label[] lbl = new Label[numero];

            for (int i = 0; i < lbl.Length; i++)
            {
                lbl[i] = new Label();
                Frm.Controls.Add(lbl[i]);
                lbl[i].BorderStyle = BorderStyle.FixedSingle;
                lbl[i].BackColor = Color.White;
                lbl[i].Text = (1+i).ToString();
                lbl[i].Location = new Point(lbl[i].Width * (i % colonne), lbl[i].Height * (i / colonne));
                lbl[i].Visible = true;
            }

           

        }
        
    }

C#: aggiunta di una label a un form a runtime.

    class Modificatore
    {

        public static void modifica(Form Frm)
        {
            Label lbl = new Label();
            Frm.Controls.Add(lbl);
            lbl.Text = "CIAO";
            lbl.AutoSize = false;
            lbl.BorderStyle = BorderStyle.FixedSingle;
            lbl.BackColor = Color.White;
            lbl.Location = new Point(100, 100);
            lbl.Width = 200;
            lbl.Height = 100;
            lbl.Visible = true;

        }
        
    }

C#: una classe con metodi statici per modificare un form dall'esterno senza bisogno di istanziarla.

Una classe con metodi statici per modificare il form dall'esterno senza istanziare nulla:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace WindowsFormsApplication4
{
    class Modificatore
    {

        public static void modifica(Form Frm)
        {
            Frm.BackColor = Color.Red;
            Frm.Width = 500;
            Button btt = new Button();
            Frm.Controls.Add(btt);
            btt.BackColor = Color.Blue;
            btt.Visible = true;
        }
        
    }
}
...il cui metodo statico va semplicemente chiamato dal costruttore del form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
   
    
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();


            Modificatore.modifica(this);
          
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }      
    }
    

}

Classe che modifica il Form



Quest'altra classe aggiunge un Button al form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{

    public class Modificatore
    {
        Form mFrm;
        public Modificatore(Form Frm)
        {
            mFrm = Frm;
        }
        public void Modifica()
        {
            Button btt = new Button();
            mFrm.Controls.Add(btt);
            btt.Width = 200;
            btt.Text = "Questo bottone è bello";
        }
    }
    
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();


            Modificatore mioModificatore = new Modificatore(this);
            mioModificatore.Modifica();
   
        }

        private void Form1_Load(object sender, EventArgs e)
        {


        }

        
      
        
    }
}


La riscriviamo:

martedì 26 agosto 2014

Far eseguire all'istanza della classe derivata il metodo overridato al modo della classe base in C#

In C# è la stessa cosa: qualora volessi far eseguire all'istanza della classe derivata il metodo overridato al modo della classe base, mi basta dichiarare una variabile del tipo della classe base ed eguagliarvi l'istanza della classe derivata:
using System;

class Classe
{
    public string nome;
    public Classe(string N)
    {
        nome = N;
    }
    public void stampaNome()
    {
        Console.WriteLine("Questo è il metodo della classe base "+nome);
        Console.ReadLine();
    }
}

class Derivata : Classe
{
    public Derivata(string N) : base(N) { }
    public void stampaNome()
    {
        Console.WriteLine("Questo è il metodo della classe derivata " + nome);
        Console.ReadLine();
    }
}

class CLass1
{

    public static void Main()
    {
        Classe miaClasse=new Classe("Classe base");
        Derivata miaDerivata=new Derivata("Classe derivata");
        miaClasse.stampaNome();
        miaDerivata.stampaNome();

        Classe vrb;
        vrb = miaDerivata;
        vrb.stampaNome();

    }
}
Questo è il metodo della classe base Classe base

Questo è il metodo della classe derivata Classe derivata

Questo è il metodo della classe base Classe derivata


Far eseguire all'istanza della classe derivata il metodo overridato al modo della classe base in C++

Vediamo di fare un discorso di ereditarietà, in C# e in C++, parallelo...

In C++, se c'è un overriding, la classe derivata esegue il metodo overriddato...
#include "iostream"
using namespace std;


class Classe{
public:
 char * nome;
 Classe(){}
 Classe(char * N){
  nome=N;
 }
 void stampaNome(){
  cout << "Nome della classe genitrice: " << nome << endl;
  getchar();
 }
};

class Derivata:public Classe{
public:
 Derivata(){}
 Derivata(char *N):Classe(N){}
 void stampaNome(){
  cout << "Nome della classe derivata: " << nome << endl;
  getchar();
 }
};
void main(){
 Classe miaClasse("Io sono la classe base");
 Derivata miaDerivata("Io sono la classe derivata");

 miaClasse.stampaNome();
 miaDerivata.stampaNome();
} 
Nome della classe genitrice: Io sono la classe base

Nome della classe derivata: Io sono la classe derivata



Se io voglio che l'istanza della classe Derivata esegua il metodo della classe genitrice:
.....

void main(){
 Classe miaClasse("Io sono la classe base");
 Derivata miaDerivata("Io sono la classe derivata");

 miaClasse.stampaNome();
 miaDerivata.stampaNome();

 Classe vrb;
 vrb=miaDerivata;
 vrb.stampaNome();
}
Nome della classe genitrice: Io sono la classe base

Nome della classe derivata: Io sono la classe derivata

Nome della classe genitrice: Io sono la classe derivata


Devo eguagliare l'istanza della classe derivata a una variabile della classe base.

sabato 23 agosto 2014

Passaggio dei parametri per valore o per riferimento, o per riferimento non inizializzato, in C#

Differenza fra classe e struttura in C# come tipo di riferimento e tipo di valore

Dimostrare che la classe è un tipo di riferimento mentre la struttura è un tipo di valore.

Costruiamo una classe, la istanziamo e quindi assegniamo l'istanza della classe a una variabile.
Leggiamo il valore di un membro della classe nell'istanza e nella variabile. Quindi modifichiamo il membro dell'istanza ma non quello della variabile.
Se il tipo è un tipo di riferimento, il membro viene cambiato sia nell'istanza che nella variabile (la variabile contiene un riferimento all'istanza)
Se il tipo è un tipo di valore, il membro viene cambiato solo nell'istanza ma non nella variabile (la variabile contiene una copia dell'istanza)

Cominciamo con la classe:
using System;
class Classe
{
    string mNome;
    public Classe(string parametro)
    {
        mNome = parametro;
    }
    public void SettaNome(string parametro)
    {
        mNome = parametro;
    }
    public void StampaNome()
    {
        Console.WriteLine(mNome);
        Console.ReadLine();
    }
}

class Class1
{
    public static void Main()
    {
        Classe Variabile;
        Classe miaClasse=new Classe("ciccio");
        Variabile = miaClasse;

        miaClasse.StampaNome();
        Variabile.StampaNome();

        miaClasse.SettaNome("Liutprando");

        miaClasse.StampaNome();
        Variabile.StampaNome();

    }
}
Ecco: ho cambiato il membro privato mNome (ma sarebbe stato più semplice cambiarne uno pubblico, vabbeh, comunque il concetto è sempre quello), da "ciccio" a "Liutprando", e il risultato è
ciccio

ciccio

Liutprando

Liutprando


ossia il membro è cambiato in ambedue: istanza e variabile.
Ora al posto di class scrivo struct, ossia invece della classe creo una struttura:
using System;
struct Classe
{
    string mNome;
    public Classe(string parametro)
    {
        mNome = parametro;
    }
    public void SettaNome(string parametro)
    {
        mNome = parametro;
    }
    public void StampaNome()
    {
        Console.WriteLine(mNome);
        Console.ReadLine();
    }
}

class Class1
{
    public static void Main()
    {
        Classe Variabile;
        Classe miaClasse=new Classe("ciccio");
        Variabile = miaClasse;

        miaClasse.StampaNome();
        Variabile.StampaNome();

        miaClasse.SettaNome("Liutprando");

        miaClasse.StampaNome();
        Variabile.StampaNome();

    }
}
E il risultato stavolta è:
ciccio

ciccio

Liutprando

ciccio


ossia il membro è cambiato solo nell'istanza ma non nella variabile, perché la variabile contiene una copia dell'istanza, e non un riferimento ad essa.

Classe semplice in C#

Iniziamo con le classi.

Creiamo una classe con membri privati.
Innanzitutto, il limitatore di accesso va messo a ogni membro:
class Classe
{
    string Nome;
    public string Cognome;
    string mestiere;
    public Classe(string Nome, string Cognome, string mestiere)
    {
        this.Nome = Nome;
        this.Cognome = Cognome;
        this.mestiere = mestiere;
    }
}

class Class1
{
    public static void Main(){
        Classe miaClasse = new Classe("mario", "rossi", "operaio");
        System.Console.WriteLine(miaClasse.Cognome);
        System.Console.ReadLine();
    }

}
rossi


Gli altri due membri sono privati.

venerdì 22 agosto 2014

Puntatori ^ a una classe in CLI

Adesso creiamo dinamicamente una istanza di una classe, prima con i puntatori tradizionali e quindi con questi "handle".
#include "stdafx.h"

using namespace System;

class Classe{
public:
	int variabile;
	Classe(int parametro){
		variabile=parametro;
	}
	void stampa(){
		Console::WriteLine(variabile);
		Console::ReadLine();
	}
};

int main(){
	Classe * miaClasse=new Classe(1234);
	miaClasse->stampa();
}
1234




#include "stdafx.h"

using namespace System;

ref class Classe{
public:
	int variabile;
	Classe(int parametro){
		variabile=parametro;
	}
	void stampa(){
		Console::WriteLine(variabile);
		Console::ReadLine();
	}
};

int main(){
	Classe ^ miaClasse = gcnew Classe(1234);
	miaClasse->stampa();
}
1234


Ecco: con questi puntatori non si usa l'operatore di deindirizzamento *, ma si usa lo stesso il -> come per i puntatori tradizionali.
Inoltre la classe deve essere dichiarata ref.

Un nuovo tipo di puntatori in CLI (managed Heap)

Puntatore.
void main(){
	int numero=123;
	int * puntatore;
	puntatore=№
	cout << numero << endl;
	cout << *puntatore << endl;
	getchar();
} 
123
123




Puntatore a una classe:
#include "iostream"
using namespace std;
class Classe{
public:
	int variabile;

	Classe(int parametro){
		variabile=parametro;
	}
	
	void scrivi(){
		cout << "scrivo" << endl;
		getchar();
	}
};

void main(){
	Classe MiaClasse(234);
	Classe * Puntatore;
	Puntatore=&MiaClasse;
	Puntatore->scrivi();
	cout << Puntatore->variabile;
	getchar();
} 
scrivo

234



Vediamo di studiare quello strano tipo di puntatori...

Innanzitutto bisogna attivare il cosiddetto CLI.
Per farlo, devo aprire un progetto CLR.
Ecco: creo un puntatore "tradizionale":
// test1 CLR.cpp : file di progetto principale.

#include "stdafx.h"

using namespace System;

int main(array<System::String ^> ^args)
{
    int numero=123;
	int * puntatore = №
	Console::WriteLine(numero);
	Console::WriteLine(*puntatore);
	Console::Read();
    return 0;
}
 
E funziona, regolarmente:
123
123


Adesso vediamo di creare quell'altro genere di puntatori...
#include "stdafx.h"

using namespace System;

int main()
{
	int numero=135;
    int ^ puntatore;
	puntatore=numero;
	Console::WriteLine(numero);
	Console::WriteLine(puntatore);
	Console::Read();
}
135
135


Sì.

Adesso confrontiamolo con il classico modo di creare un puntatore e assegnargli l'indirizzo di una variabile:
#include "stdafx.h"

using namespace System;

int main(){
	int numero=135;
    int ^ puntatore;
	puntatore=numero;

	int *puntatoreTrad;
	puntatoreTrad=№

	Console::WriteLine("Puntatore Handle");
	Console::WriteLine(numero);
	Console::WriteLine(puntatore);
	Console::WriteLine("");

	Console::WriteLine("Puntatore tradizionale");
	Console::WriteLine(numero);
	Console::WriteLine(*puntatoreTrad);
	Console::Read();
}
Puntatore Handle
135
135

Puntatore tradizionale
135
135


Sì, corrisponde perfettamente.

Adesso allochiamo dinamicamente la memoria:
#include "stdafx.h"

using namespace System;

int main(){
	int * puntatore=new int(123);

	int ^ puntatoreNuovo=gcnew int(123);

	Console::WriteLine(*puntatore);
	Console::ReadLine();
	Console::WriteLine(puntatoreNuovo);
	Console::ReadLine();
}
123

123


Sì: per allocare dinamicamente la memoria è necessario usare l'operatore gcnew.

giovedì 21 agosto 2014

System::Drawing::Size. Il form che cambia larghezza a ogni pressione sul button

Ed ecco il form che cambia larghezza alternativamente a ogni click del button:
 private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
    }
 private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    
     if(this->Size.Width<1000)
     {
      this->Size=System::Drawing::Size(1100,this->Size.Height);
     }
     else{
      this->Size=System::Drawing::Size(900,this->Size.Height);
     }
    
    }
 };

Aggiunta di un button e ridimensionamento del form

Ho inserito un button nel form.
Il codice, che viene fuori facendo doppio click sul button appena inserito, è scritto nel file Form1.h:
#pragma once

namespace MyCLRProject {

 using namespace System;
 using namespace System::ComponentModel;
 using namespace System::Collections;
 using namespace System::Windows::Forms;
 using namespace System::Data;
 using namespace System::Drawing;

 /// 
 /// Riepilogo per Form1
 /// 
 public ref class Form1 : public System::Windows::Forms::Form
 {
 public:
  Form1(void)
  {
   InitializeComponent();
   //
   //TODO: aggiungere qui il codice del costruttore.
   //
  }

 protected:
  /// 
  /// Liberare le risorse in uso.
  /// 
  ~Form1()
  {
   if (components)
   {
    delete components;
   }
  }
 private: System::Windows::Forms::Button^  button1;
 protected: 

 private:
  /// 
  /// Variabile di progettazione necessaria.
  /// 
  System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
  /// 
  /// Metodo necessario per il supporto della finestra di progettazione. Non modificare
  /// il contenuto del metodo con l'editor di codice.
  /// 
  void InitializeComponent(void)
  {
   this->button1 = (gcnew System::Windows::Forms::Button());
   this->SuspendLayout();
   // 
   // button1
   // 
   this->button1->Location = System::Drawing::Point(12, 12);
   this->button1->Name = L"button1";
   this->button1->Size = System::Drawing::Size(137, 93);
   this->button1->TabIndex = 0;
   this->button1->Text = L"button1";
   this->button1->UseVisualStyleBackColor = true;
   this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
   // 
   // Form1
   // 
   this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
   this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
   this->ClientSize = System::Drawing::Size(284, 261);
   this->Controls->Add(this->button1);
   this->Name = L"Form1";
   this->Text = L"Form1";
   this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
   this->ResumeLayout(false);

  }
#pragma endregion
 private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
    }
 private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    }
 };
}
Adesso trovo il modo di ridimensionare il form, cui va sempre fatto riferimento con this
 private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
     this->Size=System::Drawing::Size(1000,200 );
    }
 };
E funziona: alla pressione del button il form diventa largo e basso.

Progetto CLR in Visual C++

Adesso passo a progettare i form.
Non mi è molto chiaro il passaggio fra un'applicazione C++ e un'applicazione di Managed C++ e CLR.
Ho in testa una grande confusione.
Invece di impazzire, passo di palo in frasca e prendo per buona la sintassi del progetto CLR, per poi giungere in tempi successivi a riunire le cose.
A volte, anzi forse abbastanza spesso, conviene fare nell'apprendimento come fa il bambino nell'imparare a parlare.
Molto spesso, la nostra didattica inizia dall'ABC per poi andare per gradi, col risultato di fare dell'apprendimento una cosa noiosa e lenta, e poco funzionale, in quanto i concetti utili vengono imparati in un modo pesante e lento.
Conviene prima imparare come muoversi, quindi per la "grammatica" ci sarà tempo e modo di approfondire sulla base della naturale curiosità.



Ho un progetto CLS vuoto.




Quindi tramite il menu Progetto inserisco un Form, che chiamo Form1, e ottengo due files, Form1.cpp e Form1.h
Vediamo come sono composti:

Form1.cpp:
#include "Form1.h"






Form1.h:
#pragma once

namespace MyCLRProject {

 using namespace System;
 using namespace System::ComponentModel;
 using namespace System::Collections;
 using namespace System::Windows::Forms;
 using namespace System::Data;
 using namespace System::Drawing;

 /// 
 /// Riepilogo per Form1
 /// 
 public ref class Form1 : public System::Windows::Forms::Form
 {
 public:
  Form1(void)
  {
   InitializeComponent();
   //
   //TODO: aggiungere qui il codice del costruttore.
   //
  }

 protected:
  /// 
  /// Liberare le risorse in uso.
  /// 
  ~Form1()
  {
   if (components)
   {
    delete components;
   }
  }

 private:
  /// 
  /// Variabile di progettazione necessaria.
  /// 
  System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
  /// 
  /// Metodo necessario per il supporto della finestra di progettazione. Non modificare
  /// il contenuto del metodo con l'editor di codice.
  /// 
  void InitializeComponent(void)
  {
   this->SuspendLayout();
   // 
   // Form1
   // 
   this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
   this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
   this->ClientSize = System::Drawing::Size(284, 261);
   this->Name = L"Form1";
   this->Text = L"Form1";
   this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
   this->ResumeLayout(false);

  }
#pragma endregion
 private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
    }
 };
}


Bene.
Dunque il file Form1.h è il vero pezzo forte della situazione.
Ma se io faccio partire il programma ottengo un messaggio di errore:
1>------ Inizio compilazione: Progetto: MyCLRProject, Configurazione: Debug Win32 ------
1>  Form1.cpp
1>LINK : fatal error LNK1561: il punto d'ingresso deve essere definito
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========

Il punto di ingresso deve essere definito.

Nel progetto in Visual Basic ero abituato al fatto che il punto di ingresso fosse stabilito automaticamente: se non altrimenti specificato, partiva da Form1.
Invece qua bisogna definirlo specificamente.
E come si fa?

Intanto mettiamo un altro file, di tipo cpp:
#include "Form1.h"

using namespace MyCLRProject;

int main(){
 Form1 frm;
 frm.ShowDialog();
 return 0;
}
Qui il comportamento è praticamente lo stesso che sono abituato a vedere con il C++.
Data una classe Form1, viene istanziato un oggetto frm di classe Form1, e viene chiamato il suo metodo ShowDialog().
E appare il form vuoto (su una finestra di DOS).

giovedì 14 agosto 2014

Interfaccia unica implementata da classi derivate di classi astratte completamente diverse.

Se io ho il concetto generico di Animale, da questo concetto generico derivano i concetti particolari di Cavallo, Bue, Gatto, Cane, Asino... Però soltanto alcuni di questi possono essere impiegati per trainare un carro. Inoltre per trainare un carro può essere impiegato anche un Motore, concetto diverso da quello di Animale. Quindi alcune classi di Animali e la classe Motore implementano l'interfaccia Trainatore. Altre classi di Animali, invece, non la implementano, come Cane e Gatto, che non vengono impiegati per trainare nulla.

Anzi posso usare il concetto astratto di VeicoloMotorizzato, di cui fanno parte le classi Trattore, Motoscafo, Aereo, delle quali soltanto la classe Trattore implementa l'interfaccia Trainatore. Ecco un esempio più chiaro che mi aiuta a capire bene a che servono le interfacce: la funzione che mette in opera il trainamento accetta un parametro di tipo puntatore a Trainatore, in modo che le si possa dare in pasto sia una classe derivata dal concetto astratto di Animale, come Cavallo, Bue o Asino, sia una classe derivata dal concetto astratto di VeicoloMotorizzato come Trattore (ma non Cane o Gatto, o, rispettivamente, Motoscato o Aereo, che non implementano l'interfaccia Trainatore)
#include "iostream"
using namespace std;


class Animale{
public:
 virtual void muoviti()=0;
 virtual void verso() =0;
 
};

class Trainatore{
public:
 virtual void azione()=0;
};

class Cavallo:public Animale,public Trainatore{
 void muoviti(){
  cout << "io galoppo" << endl;
  getchar();
 }
 void verso(){
  cout << "io nitrisco" << endl;
  getchar();
 }
 void azione(){
  cout << "io traino il carro velocemente" << endl;
  getchar();
 }
};

class Bue:public Animale,public Trainatore{
 void muoviti(){
  cout << "io cammino" << endl;
  getchar();
 }
 void verso(){
  cout << "io muggisco" << endl;
  getchar();
 }
 void azione(){
  cout << "io traino il carro lentamente" << endl;
  getchar();
 }
};

class Gatto:public Animale{
public:
 void muoviti(){
  cout << "io cammino felpato" << endl;
  getchar();
 }
 void verso(){
  cout << "io miagolo" << endl;
  getchar();
 }
};
class VeicoloMotorizzato{
public:
 virtual void carburante()=0;
 virtual void mezzo()=0;
};

class Motoscafo:public VeicoloMotorizzato{
 void carburante(){
  cout << "benzina" << endl;
  getchar();
 }
 void mezzo(){
  cout << "mare" << endl;
  getchar();
 }
};

class Aereo:public VeicoloMotorizzato{
 void carburante(){
  cout << "kerosene" << endl;
  getchar();
 }
 void mezzo(){
  cout << "aria" << endl;
  getchar();
 }
};

class Trattore:public VeicoloMotorizzato,public Trainatore{
 void carburante(){
  cout << "gasolio" << endl;
  getchar();
 }
 void mezzo(){
  cout << "campagna" << endl;
  getchar();
 }
 void azione(){
  cout << "traino il carro molto velocemente" << endl;
  getchar();
 }
};

void trazione(Trainatore * anim){
 anim->azione();
}

void main(){
 Cavallo Furia;
 Bue Filippo;
 Gatto Silvestro;
 Aereo Jumbo;
 Motoscafo Barchetta;
 Trattore Nicolino;

 trazione(&Furia);
 trazione(&Filippo);
 trazione(&Nicolino);
} 
io traino il carro velocemente

io traino il carro lentamente

traino il carro molto velocemente


Perfezionamento delle classi astratte usate come interfacce in C++

Ecco: più appropriato che la classe astratta usata come interfaccia possieda una funzione che la classe astratta da cui derivano le classi dei vari animali non possiede. Così dalla classe astratta Animale faccio derivare pure la classe Gatto che non implementa l'interfaccia Trainatore in quanto, come è noto, il gatto non viene impiegato per trainare alcunché!
#include "iostream"
using namespace std;


class Animale{
public:
 virtual void muoviti()=0;
 virtual void verso() =0;
 
};

class Trainatore{
public:
 virtual void azione()=0;
};

class Cavallo:public Animale,public Trainatore{
 void muoviti(){
  cout << "io galoppo" << endl;
  getchar();
 }
 void verso(){
  cout << "io nitrisco" << endl;
  getchar();
 }
 void azione(){
  cout << "io traino il carro velocemente" << endl;
  getchar();
 }
};

class Bue:public Animale,public Trainatore{
 void muoviti(){
  cout << "io cammino" << endl;
  getchar();
 }
 void verso(){
  cout << "io muggisco" << endl;
  getchar();
 }
 void azione(){
  cout << "io traino il carro lentamente" << endl;
  getchar();
 }
};

class Gatto:public Animale{
public:
 void muoviti(){
  cout << "io cammino felpato" << endl;
  getchar();
 }
 void verso(){
  cout << "io miagolo" << endl;
  getchar();
 }
};
class Motore:public Trainatore{
public:
 void rifornimento(){
  cout << "voglio benzina" << endl;
  getchar();
 }
 void azione(){
  cout << "io traino il carro molto velocemente" << endl;
  getchar();
 }
};

void trazione(Trainatore * anim){
 anim->azione();
}

void main(){
 Cavallo Furia;
 Bue Filippo;
 Motore mioMotore;
 trazione(&Furia);
 trazione(&Filippo);
 trazione(&mioMotore);
} 

Ereditarietà multipla da classi astratte usate come interfacce in C++

Ecco: ho alcuni oggetti che ereditano dalla classe astratta Animale, che implementano la classe astratta Trainatore. E ho anche una classe Motore, completamente diversa quanto a membri, che implementa ugualmente la classe astratta Trainatore.
#include "iostream"
using namespace std;


class Animale{
public:
 virtual void muoviti()=0;
 virtual void verso() =0;
 virtual void azione() =0;
};

class Trainatore{
public:
 virtual void azione()=0;
};

class Cavallo:public Animale,public Trainatore{
 void muoviti(){
  cout << "io galoppo" << endl;
  getchar();
 }
 void verso(){
  cout << "io nitrisco" << endl;
  getchar();
 }
 void azione(){
  cout << "io traino il carro velocemente" << endl;
  getchar();
 }
};

class Bue:public Animale,public Trainatore{
 void muoviti(){
  cout << "io cammino" << endl;
  getchar();
 }
 void verso(){
  cout << "io muggisco" << endl;
  getchar();
 }
 void azione(){
  cout << "io traino il carro lentamente" << endl;
  getchar();
 }
};

class Motore:public Trainatore{
public:
 void rifornimento(){
  cout << "voglio benzina" << endl;
  getchar();
 }
 void azione(){
  cout << "io traino il carro molto velocemente" << endl;
  getchar();
 }
};

void trazione(Trainatore * anim){
 anim->azione();
}

void main(){
 Cavallo Furia;
 Bue Filippo;
 Motore mioMotore;
 trazione(&Furia);
 trazione(&Filippo);
 trazione(&mioMotore);
} 
io traino il carro velocemente

io traino il carro lentamente

io traino il carro molto velocemente


Sì.
Implementano l'interfaccia in quanto istanziano la funzione virtuale pura "azione()". Quindi la funzione che ne mostra i diversi modi di espletare la funzione "azione()" può assumere come parametro un puntatore del tipo della classe astratta Trainatore, che vale pure per un oggetto di una classe completamente diversa da Animale, come Motore.

martedì 12 agosto 2014

Classe astratta derivata da un'altra classe astratta.

Grandioso!

Ho creato una classe astratta FiguraSolida che eredita dalla classe astratta Figura!
Sembra che sia tutto ben fatto:
#include "iostream"
using namespace std;


class Figura{
protected:
 int base,altezza;
public:
 Figura(){}
 Figura(int b,int a){
  base=b;altezza=a;
 }
 virtual int area()=0;
};

class Quadrato:public Figura{
public:
 Quadrato(int b){
  base=b;
 }
 int area(){
  return base*base;
 }
};
class Rettangolo:public Figura{
public:
 Rettangolo(int b, int a):Figura(b,a){}
 int area(){
  return base*altezza;
 }
};

class Triangolo:public Figura{
public:
 Triangolo(int b, int a):Figura(b,a){}
 int area(){
  return base*altezza/2;
 }
};

class FiguraSolida:public Figura{
protected:
 int profondita;
public:
 FiguraSolida(int b, int a, int p){
  base=b;
  altezza=a;
  profondita=p;
 }
 virtual int volume()=0;
};

class Parallelepipedo:public FiguraSolida{
public:
 Parallelepipedo(int b, int a, int p):FiguraSolida(b,a,p){
 }
 int area(){
  return base*altezza;
 }
 int volume(){
  return area()*profondita;
 }
};
void StampaArea(Figura *fig){
 cout << fig->area() << endl;
 getchar();
}

void main(){
 Parallelepipedo par(3,4,5);
 cout << par.volume() << endl;
 cout << par.area() << endl;
 getchar();

} 
60
12


E infatti ho il volume del parallelepipedo 3 * 4 * 5 =60, e l'area della base 3 * 4 = 12.

Aggiunta della classe derivata Quadrato, con un solo parametro nel costruttore, all'esercizio precedente.

Aggiungo un'altra figura geometrica, Quadrato, che ha un costruttore con un solo parametro:
#include "iostream"
using namespace std;


class Figura{
protected:
 int base,altezza;
public:
 Figura(){}
 Figura(int b,int a){
  base=b;altezza=a;
 }
 virtual int area()=0;
};

class Quadrato:public Figura{
public:
 Quadrato(int b){
  base=b;
 }
 int area(){
  return base*base;
 }
};
class Rettangolo:public Figura{
public:
 Rettangolo(int b, int a):Figura(b,a){}
 int area(){
  return base*altezza;
 }
};

class Triangolo:public Figura{
public:
 Triangolo(int b, int a):Figura(b,a){}
 int area(){
  return base*altezza/2;
 }
};

void StampaArea(Figura *fig){
 cout << fig->area() << endl;
 getchar();
}

void main(){
 Rettangolo rect(3,4);
 Triangolo tri (3,4);
 Quadrato qua(3);
 StampaArea(&rect);
 StampaArea(&tri);
 StampaArea(&qua);

}
Funziona ugualmente.
12

6

9


Ho creato ex novo un costruttore per la classe Quadrato.
Per farlo, ho dovuto riscrivere il costruttore di default per la classe base, altrimenti ricevevo un messaggio di errore.
Indagherò meglio sui motivi per cui si deve fare questo...

Classe astratta Figura geometrica e sue derivate Rettangolo e Triangolo in C++. (esercizio elementare)

Bene...

E dopo aver elucubrato in modo piuttosto ossessivo con i concetti di cui sopra e anche più, dopo essermi convinto che avevo capito davvero la cosa nonostante il mio parere contrario, inizio a mimare la realtà con il C++.

Ho un concetto astratto di Figura geometrica, che si concretizza in due concetti concreti di rettangolo e triangolo:
#include "iostream"
using namespace std;


class Figura{
protected:
 int base,altezza;
public:
 Figura(int b,int a){
  base=b;altezza=a;
 }
 virtual int area()=0;
};

class Rettangolo:public Figura{
public:
 Rettangolo(int b, int a):Figura(b,a){}
 int area(){
  return base*altezza;
 }
};

class Triangolo:public Figura{
public:
 Triangolo(int b, int a):Figura(b,a){}
 int area(){
  return base*altezza/2;
 }
};

void StampaArea(Figura *fig){
 cout << fig->area() << endl;
 getchar();
}

void main(){
 Rettangolo rect(3,4);
 Triangolo tri (3,4);
 StampaArea(&rect);
 StampaArea(&tri);

} 
La funzione StampaArea si serve del polimorfismo accettando come parametro un puntatore del tipo classe base astratta genitrice delle classi Rettangolo e Triangolo.
Mi sembra tutto privo di problemi...
12

6


sabato 9 agosto 2014

Ripasso sui membri privati della classe genitrice.

Ripassiamo queste eventualità, cercando di schematizzare:
  1. la classe Genitrice ha una proprietà privata;
    1. accesso da un metodo della classe Genitrice;
    2. accesso da un metodo della classe Derivata
    3. accesso da un metodo della classe Derivata che overridda un metodo della classe Genitrice.
  2. la classe Genitrice ha una proprietà privata e la classe Derivata ha una proprietà con lo stesso nome:
    1. accesso da un metodo della classe Genitrice;
    2. accesso da un metodo della classe Derivata;
    3. accesso da un metodo della classe Derivata che overridda un metodo della classe Genitrice.
Ripassiamo queste:

La classe Genitrice ha una proprietà privata: ne saggiamo l'accesso da un metodo della classe Genitrice
#include "iostream"
using namespace std;


class Genitrice{
  char * proprieta;
public:
 Genitrice(){
 proprieta="io sono la proprieta' della genitrice";
 }
void metodoGen(){
 cout << "io sono il metodo della genitrice, " << proprieta << endl;
 getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){
 }
};

void main(){
 Genitrice Gen;
 Derivata der;
 Gen.metodoGen();
} 
io sono il metodo della genitrice, io sono la proprieta' della genitrice


Dicendo "io sono il metodo della genitrice" si esprime il fatto che è stato chiamato il metodo della classe Genitrice; dicendo "io sono la proprietà della genitrice" si esprime il fatto che il metodo ha messo a video la proprietà della classe Genitrice.
La classe Genitrice ha una proprietà privata: ne saggiamo l'accesso da un metodo della classe Derivata
#include "iostream"
using namespace std;


class Genitrice{
  char * proprieta;
public:
 Genitrice(){
 proprieta="io sono la proprieta' della genitrice";
 }
void metodoGen(){
 cout << "io sono il metodo della genitrice, " << proprieta << endl;
 getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){
 }
 void metodoDer(){
  cout << "Io sono il metodo della derivata, " << proprieta << endl;
 }

};

void main(){
 Genitrice Gen;
 Derivata der;
 der.metodoDer();
} 
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(22): error C2248: 'Genitrice::proprieta': impossibile accedere a private membro dichiarato nella classe 'Genitrice'
Ecco, in questo caso, essendo la proprietà privata della classe Genitrice, il metodo della classe Derivata non la vede.
Ma dal momento che il metodo della classe Genitrice è ereditato dalla classe Derivata, posso chiamare questo metodo anche dalla classe Derivata:
void main(){
 Genitrice Gen;
 Derivata der;
 der.metodoGen();
}
io sono il metodo della genitrice, io sono la proprieta' della genitrice


Ho dovuto togliere il metodo metodoDer() in quanto avevo un codice di errore in quanto la definizione del metodo fa riferimento a una proprietà inaccessibile.
La classe Genitrice ha una proprietà privata: ne saggiamo l'accesso da un metodo della classe Derivata che overridda un metodo con lo stesso nome della classe Genitrice.
#include "iostream"
using namespace std;


class Genitrice{
  char * proprieta;
public:
 Genitrice(){
 proprieta="io sono la proprieta' della genitrice";
 }
void metodo(){
 cout << "io sono il metodo della genitrice, " << proprieta << endl;
 getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){
 }
 void metodo(){
 cout << "io sono il metodo della derivata, " << proprieta << endl;
 getchar();
 }

};

void main(){
 Genitrice Gen;
 Derivata der;
 der.metodo();
}
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(22): error C2248: 'Genitrice::proprieta': impossibile accedere a private membro dichiarato nella classe 'Genitrice'
Era ovvio: già nella definizione del metodo l'intellisense dà errore per membro inaccessibile.
Dunque la classe Derivata non può overriddare: se si elimina la definizione del metodo nella classe Derivata è:
io sono il metodo della genitrice, io sono la proprieta' della genitrice



L'overriding zittisce il metodo della classe genitrice.

venerdì 8 agosto 2014

Prove sull'overriding delle proprietà protected.

Bene.
Adesso, invece del public mettiamoci il protected: credo che sia esattamente la stessa cosa del public, visto che una proprietà protected è visibile dalla classe derivata.

Ricominciamo:
Proprietà protected overridata:
#include "iostream"
using namespace std;


class Genitrice{
protected:
	char * proprieta;
public:
 
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodo(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
protected:
	 char * proprieta;
public:

 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodo(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodo();
 der.metodo();

}
sono la proprieta' della genitrice

sono la proprieta' della derivata


Proprietà protected overridata letta con un metodo della classe genitrice e uno diverso della classe derivata:
#include "iostream"
using namespace std;


class Genitrice{
protected:
	char * proprieta;
public:
 
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
protected:
	 char * proprieta;
public:

 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodoGen();
 der.metodoDer();

}
sono la proprieta' della genitrice

sono la proprieta' della derivata


Leggiamole usando metodoGen ereditato dalla classe derivata, e il risultato dovrebbe essere lo stesso:
void main(){
 Genitrice gen;
 Derivata der;
 der.metodoGen();
 der.metodoDer();

}
infatti...
sono la proprieta' della genitrice

sono la proprieta' della derivata




Togliamo la proprietà dalla classe derivata:
#include "iostream"
using namespace std;


class Genitrice{
protected:
	char * proprieta;
public:
 
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{


public:

 Derivata():Genitrice(){

 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodoGen();
 der.metodoGen();
 der.metodoDer();

}
sono la proprieta' della genitrice

sono la proprieta' della genitrice

sono la proprieta' della genitrice


Chiamandole direttamente:
void main(){
 Genitrice gen;
 Derivata der;
 cout << gen.proprieta << endl;
 cout << der.proprieta << endl;
 getchar();

} 
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(38): error C2248: 'Genitrice::proprieta': impossibile accedere a protected membro dichiarato nella classe 'Genitrice'
Ecco: la differenza è solo che la proprietà protected non può essere chiamata dall'esterno della classe derivata in quanto si comporta come una proprietà privata quando chiamata dall'esterno.

Prove sull'overriding delle proprietà pubbliche di una classe.

Overridiamo una proprietà pubblica...

#include "iostream"
using namespace std;


class Genitrice{
 
public:
 char * proprieta;
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodo(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
 
public:
 char * proprieta;
 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodo(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodo();
 der.metodo();

}

sono la proprieta' della genitrice

sono la proprieta' della derivata


Ho messo pubblica una proprietà e l'ho ridefinita nella classe derivata.
Se istanzio la classe genitrice viene letta la proprietà della classe genitrice, mentre se istanzio la classe derivata, che overridda il metodo, questo legge la proprietà della classe derivata e non più quella della genitrice.
Anziché overriddare il metodo, creo due metodi con nome diverso che mettano a video la proprietà, un nome nella classe genitrice e uno nella classe derivata.
#include "iostream"
using namespace std;


class Genitrice{
 
public:
 char * proprieta;
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
 
public:
 char * proprieta;
 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodoGen();
 der.metodoDer();

}
sono la proprieta' della genitrice

sono la proprieta' della derivata


Anche così il comportamento è lo stesso.
Dunque un metodo della classe genitrice vede la proprietà della classe genitrice, mentre un metodo della classe derivata vede la proprietà overriddata della classe derivata.

Essendo la proprietà pubblica, possiamo anche chiamarla direttamente:
#include "iostream"
using namespace std;


class Genitrice{
 
public:
 char * proprieta;
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
 
public:
 char * proprieta;
 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 cout << gen.proprieta << endl;
 getchar();
 cout << der.proprieta << endl;
 getchar();

} 
sono la proprieta' della genitrice

sono la proprieta' della derivata




Adesso proviamo a eseguire il metodo della classe genitrice dalla genitrice e dalla derivata e vediamo quale proprietà vede:
#include "iostream"
using namespace std;


class Genitrice{
 
public:
 char * proprieta;
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
 
public:
 char * proprieta;
 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodoGen();
 der.metodoGen();
}
sono la proprieta' della genitrice

sono la proprieta' della genitrice


Vede sempre la proprietà della classe genitrice anche quando viene eseguito dalla classe derivata.


Se togliamo la proprietà dalla classe derivata, anche da questa si dovrebbe avere accesso a quella della classe genitrice.
Proviamo:
#include "iostream"
using namespace std;


class Genitrice{
 
public:
 char * proprieta;
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
 
public:

 Derivata():Genitrice(){
  
 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodoGen();
 der.metodoDer();

}
sono la proprieta' della genitrice

sono la proprieta' della genitrice


Da qui possiamo comprendere meglio:
Dunque, una proprietà pubblica può essere ereditata dalla classe derivata, ma overridata. Nel caso sia overridata, però, la classe genitrice vede sempre la proprietà "sua", anche quando il metodo della classe genitrice venga chiamato dalla classe derivata.
Proviamo a evocarlo direttamente.
void main(){
 Genitrice gen;
 Derivata der;
 cout << gen.proprieta << endl;
 getchar();
 cout << der.proprieta << endl;
 getchar();
}
sono la proprieta' della genitrice

sono la proprieta' della genitrice


In pratica non ci sono molte novità...
L'unica cosa notevole, che non mi risultava molto immediata, è che un metodo della classe genitrice vede la proprietà della classe genitrice, non overridata.
Cominciamo a entrare in confidenza con il meccanismo... lo sto spremendo come un limone (quando ho tempo di concentrarmi con calma!)

mercoledì 6 agosto 2014

L'immagine delle scatole per capire bene l'ereditarietà in C++

Dunque...
La classe genitrice è come una scatola compresa entro una scatola più grande che è la classe derivata.
La classe derivata sarà di necessità più grande della genitrice, contenendola.

Immagino la genitrice come una scatola di vetro in parte opaco e in parte trasparente, a seconda che la classe derivata abbia o no accesso ai suoi membri
class Genitrice{
 char * privata;
public:
 Genitrice(){
  privata="sono privata";
 }
 void metodo(){
  cout << privata << endl;
  getchar();
 }
};
Ecco, qui il membro privata non è visibile all'esterno, ma è visibile dall'interno della classe, anche quando questa è compresa in una "scatola" più grande che è la classe derivata.
Dato che il metodo metodo è visibile anche dall'ambiente della scatola più grande, si può fare leva su di esso per agire sul membro privata che è invisibile dall'ambiente della scatola più grande.

Provo a sbizzarrirmi un po'...

#include "iostream"
using namespace std;


class Genitrice{
 char * privata;
public:
 Genitrice(){
  privata="sono privata";
 }
 void metodo(){
  cout << privata << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){}
 void altrometodo(){
  cout << "altro metodo" << endl;
  getchar();
 }

};




void main(){
 Genitrice gen;
 Derivata der;
 der.metodo();
}
Ecco: la classe derivata non overridda il metodo metodo, per cui quando si chiama il metodo della classe derivata si fa riferimento al contenuto della scatola più piccola che si trova nella parte visibile di essa, il quale ha accesso a tutti i membri della scatola più piccola, e quindi anche alla variabile privata, che si trova nella parte opaca della scatola più piccola.

Adesso, invece, overriddiamo metodo: questo si può paragonare a un taglio operato sulla scatola più piccola, dove viene troncata la parte trasparente dove risiede il metodo metodo e al posto di essa viene messo un analogo metodo metodo appartenente però all'ambiente della scatola più grande, e che quindi non ha accesso alla parte opaca della scatola più piccola.
#include "iostream"
using namespace std;


class Genitrice{
 char * privata;
public:
 Genitrice(){
  privata="sono privata";
 }
 void metodo(){
  cout << privata << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){}
 void metodo(){
  cout << privata << endl;
  getchar();
 }
 void altrometodo(){
  cout << "altro metodo" << endl;
  getchar();
 }

};




void main(){
 Genitrice gen;
 Derivata der;
 der.metodo();
} 
Ottengo l'errore già con l'intelliSense...

Ecco l'output, comunque:
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(21): error C2248: 'Genitrice::privata': impossibile accedere a private membro dichiarato nella classe 'Genitrice'
Certo: perché adesso il metodo metodo si trova nell'ambiente della scatola esterna, e non ha più accesso al membro privata della parte opaca della scatola più piccola, dove invece aveva accesso il metodo non overriddato in quanto appartenente alla scatola più piccola.

martedì 5 agosto 2014

Accesso a membri privati della classe genitrice da metodi della classe genitrice ma non della classe derivata.

Scopro un'altra cosa che non mi era mai venuta in mente.
Una classe derivata non può accedere con metodi suoi ai membri privati della classe genitrice.
Con metodi ereditati, invece, vi può accedere!

Ecco:
#include "iostream"
using namespace std;


class Genitrice{
 char * privata;
public:
 Genitrice(){
  privata="sono privata";
 }
 void metodo(){
  cout << privata << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){}

};




void main(){
 Genitrice gnt;
 gnt.metodo();
 Derivata drv;
 drv.metodo();
}
Ecco:
sono privata

sono privata


Invocando nella classe derivata il metodo ereditato dalla classe genitrice, esso vede il membro privato della classe genitrice.
Adesso overriddo il metodo:
#include "iostream"
using namespace std;


class Genitrice{
 char * privata;
public:
 Genitrice(){
  privata="sono privata";
 }
 void metodo(){
  cout << privata << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){}
 void metodo(){
  cout << privata << endl;
  getchar();
 }

};




void main(){
 Genitrice gnt;
 gnt.metodo();
 Derivata drv;
 drv.metodo();
}
Ecco, adesso la classe derivata overridda il metodo, ripetendolo esattamente uguale, ma appartenente ad essa, non alla classe genitrice.
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(21): error C2248: 'Genitrice::privata': impossibile accedere a private membro dichiarato nella classe 'Genitrice'
Ecco, come volevasi dimostrare!

La variabile di classe genitrice, eguagliata alla classe derivata, contiene le proprietà della classe derivata?

Bene.
Ho una classe genitrice, non astratta: qualcosa che può generare eredi, ma che può esistere anche di per sè.

Dal momento che si può eguagliare una variabile di un tipo classe a un oggetto di una classe derivata, voglio vedere cosa è in comune fra la variabile di classe genitrice e la variabile di classe derivata.

Creo una classe genitrice di tipo "Medico" che sarebbe il medico generico, il quale non è un'idea astratta, ma può esistere nella realtà, quindi è da definire con una classe non astratta.
La classe derivata è "Radiologo", il quale possiede una variabile "specialita", non posseduta dalla classe genitrice, e mentre il Medico diagnostica visitando il Radiologo overloada il metodo con "referta le radiografie".

Istanziamo il Radiologo e poi creiamo una variabile di tipo Medico, che eguagliamo a Radiologo, per vedere se contiene la variabile "specialita".
#include "iostream"
using namespace std;


class Medico{
public:
 
 

 void diagnostica(){
  cout << "visita" << endl;
  getchar();
 }
};

class Radiologo:public Medico{

 
public:
 char * specialita;
 Radiologo(){
  specialita="radiologia";
 }
 void diagnostica(){
  cout << "referta le radiografie" << endl;
  getchar();
 }
};


void main(){
 Radiologo Pippo;
 cout << Pippo.specialita << endl;
 getchar();
 Medico mdc;
 mdc=Pippo;
 cout << mdc.specialita << endl;
 getchar();
} 
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(37): error C2039: 'specialita': non è un membro di 'Medico'
Dunque la variabile di classe genitrice, eguagliata a quella di classe derivata, non contiene le proprietà della classe derivata.

sabato 2 agosto 2014

Seguiamo l'esempio di Wikipedia per quanto riguarda il polimorfismo.
Abbiamo una classe astratta Animale, e due classi derivate da questa, Cane e Gatto.
Creiamole...
#include "iostream"
using namespace std;

class Animale{
public:
	virtual void CosaMangia()=0;
};

class Cane: public Animale{
public:
	void CosaMangia(){
		cout << "Osso" << endl;
		getchar();
	}
};

class Gatto: public Animale{
public:
	void CosaMangia(){
		cout << "Pesce" << endl;
		getchar();
	}
};
Ecco: proviamo a istanziare...
void main(){
	Animale * mioAnimale;
	mioAnimale= new Cane();
	mioAnimale->CosaMangia();
	delete mioAnimale;
	mioAnimale=new Gatto();
	mioAnimale->CosaMangia();
	delete mioAnimale;

}
Ecco l'output:
Osso

Pesce




Ora dovrei costruire una funzione che prende come parametro un puntatore di tipo Animale...

void funzione(Animale * animal){
	animal->CosaMangia();
}

void main(){
	Cane * mioCane=new Cane();
	Gatto * mioGatto=new Gatto();
	funzione(mioCane);
	funzione(mioGatto);
}
E funziona:
Osso

Pesce