sabato 12 luglio 2014

Istanza della classe e oggetto puntato dal puntatore come cosa unica e non diverse istanze della classe.

Adesso vediamo se, creando un puntatore e attribuendovi l'indirizzo dell'istanza della classe, la variabile puntata dal puntatore è la stessa cosa dell'istanza della classe o una sua copia.
Il procedimento è molto semplice:
void main(){

 Triangolo mioTriangolo(3,4);
 Triangolo * vrbl;
 vrbl=&mioTriangolo;

 cout << mioTriangolo.area() << endl;
 cout << vrbl->area() << endl;
 vrbl->modificaBase();
 cout<< mioTriangolo.area() << endl;
 cout << vrbl->area() << endl;
 getchar();
}
6
6
246
246


Nel momento in cui è scattata la funzione modificaBase, si modifica sia l'area dell'istanza mioTriangolo sia quella dell'oggetto puntato dal puntatore. Questo significa che diversamente dalle variabili con i puntatori non si crea una nuova istanza della classe, ma viene puntata sempre la stessa.

Come mi aspettavo dalle mie reminiscenze di C++.

Istanza di una classe e variabile cui è stato attribuito il valore di quella istanza: cosa unica o due diverse istanze?

Variabile come nuova istanza della classe.

Aggiungo nella classe una funzione che modifica la base della figura:
class Rettangolo{
protected:
 int base,altezza;
public:
 Rettangolo(){}
 Rettangolo(int b, int a){
  base=b;
  altezza=a;
 }
 void modificaBase(){
  base=123;
 }
 int area(){
  return base*altezza;
 }
};
E adesso, per vedere se la variabile mioTriangolo e la variabile vrbl di tipo Triangolo che ho creato e cui ho attribuito il valore di mioTriangolo sono la stessa cosa o due istanze diverse della classe, faccio così:
void main(){

 Triangolo mioTriangolo(3,4);
 Triangolo vrbl;
 vrbl=mioTriangolo;

 cout << mioTriangolo.area() << endl;
 cout << vrbl.area() << endl;
 vrbl.modificaBase();
 cout<< mioTriangolo.area() << endl;
 cout << vrbl.area() << endl;
 getchar();
}

}
Creo una istanza mioTriangolo della classe Triangolo e poi una variabile vrbl di tipo Triangolo cui attribuisco il valore dell'istanza mioTriangolo.
Quindi metto a video l'area di mioTriangolo e di vrbl, faccio scattare nella variabile vrbl la funzione modificaBase e quindi rimetto a video l'area di mioTriangolo e di vrbl.
6
6
6
246

Ecco: sono due cose diverse.

Variabili oggetto di classi base e derivate.

Quindi, riepiloghiamo.

Posso creare una variabile di tipo classe base.
A questa variabile posso attribuire l'oggettoistanza di una classe derivata.

 Triangolo mioTriangolo(3,4);
 Rettangolo vrbl;
 vrbl=mioTriangolo;
Il codice funziona.
Adesso creo una classe Foo, che non fa parte della "famiglia":
class Foo{
protected:
 int ciccia;
public:
 Foo(int c){
  ciccia=c;
 }
};
E vediamo se una variabile di tipo Rettangolo (classe base) può accettare un valore di un'istanza della classe Foo.

 Triangolo mioTriangolo(3,4);
 Foo mioFoo(3);

 Rettangolo vrbl;
 vrbl=mioFoo;
1>------ Inizio compilazione: Progetto: test1, Configurazione: Debug Win32 ------
1>  foglio.cpp
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(42): error C2679: '=' binario: non è stato trovato alcun operatore che accetti un operando destro di tipo 'Foo'. È anche possibile che non vi siano conversioni accettabili.
1>          c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(16): potrebbe essere 'Rettangolo &Rettangolo::operator =(const Rettangolo &)'
1>          durante la ricerca di corrispondenza con l'elenco di argomenti '(Rettangolo, Foo)'
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========
Ecco: non è possibile una conversione.
Posso quindi creare una variabile di tipo classe base e attribuire un oggetto istanza di una classe derivata, ma non posso attribuire un oggetto istanza di una classe diversa.
E vediamo se posso creare una variabile di tipo classe derivata e attribuirle un oggetto istanza di una classe base
 Rettangolo mioRettangolo(3,4);

 Triangolo vrbl;

 vrbl=mioRettangolo;
1>------ Inizio compilazione: Progetto: test1, Configurazione: Debug Win32 ------
1>  foglio.cpp
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(42): error C2679: '=' binario: non è stato trovato alcun operatore che accetti un operando destro di tipo 'Rettangolo'. È anche possibile che non vi siano conversioni accettabili.
1>          c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(27): potrebbe essere 'Triangolo &Triangolo::operator =(const Triangolo &)'
1>          durante la ricerca di corrispondenza con l'elenco di argomenti '(Triangolo, Rettangolo)'
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========
No: l'inverso non si può fare.

giovedì 10 luglio 2014

Studio delle funzioni virtuali con le variabili oggetto.

Ho due classi, una classe base Rettangolo e una classe derivata Triangolo.
#include "iostream"
using namespace std;

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

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

void main(){
	Triangolo mioTriangolo(3,4);
	Triangolo vrbl;
	vrbl=mioTriangolo;
	cout << vrbl.area() << endl;
	

	getchar();
}
Ho creato una variabile Triangolo e vi attribuisco il valore dell'oggetto mioTriangolo che ho creato istanziando la classe.
Vediamo come si comporta.

6


Si comporta come un triangolo.

Adesso creo una variabile Rettangolo e vi attribuisco il valore dell'oggetto mioTriangolo.
void main(){
	Triangolo mioTriangolo(3,4);
	Rettangolo vrbl;
	vrbl=mioTriangolo;
	cout << vrbl.area() << endl;
	

	getchar();
}
12


Si comporta come un rettangolo.
Rendiamo virtuale la funzione nella classe base.
class Rettangolo{
protected:
	int base,altezza;
public:
	Rettangolo(){}
	Rettangolo(int b, int a){
		base=b;
		altezza=a;
	}
	virtual int area(){
		return base*altezza;
	}
};


Creiamo di nuovo la variabile, prima di tipo Triangolo e dopo di tipo Rettangolo.
void main(){
	Triangolo mioTriangolo(3,4);
	Triangolo vrbl;
	vrbl=mioTriangolo;
	cout << vrbl.area() << endl;
	

	getchar();
}
6


Si comporta come un triangolo.

Ora creiamo una variabile Rettangolo:
void main(){
	Triangolo mioTriangolo(3,4);
	Rettangolo vrbl;
	vrbl=mioTriangolo;
	cout << vrbl.area() << endl;
	

	getchar();
}
12


Si comporta come un rettangolo.

Dunque, se la funzione non è virtuale, se si attribuisce il valore di un oggetto della classe derivata a una variabile del tipo della classe derivata, la variabile si comporta come oggetto della classe derivata. Se la funzione è virtuale, se si attribuisce il valore di un oggetto della classe derivata a una variabile del tipo della classe base la variabile si comporta come un oggetto della classe base.

mercoledì 9 luglio 2014

Classe base che viene istanziata ed ereditata.

Adesso mi esercito a creare una classe base che viene istanziata ed ereditata.
Per essere istanziata, non deve essere una classe generica... Facciamo che sia un rettangolo, che derivi la classe Triangolo.

#include "iostream"
using namespace std;

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

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

void main(){
	Rettangolo mioRettangolo(3,4);
	Triangolo mioTriangolo(3,4);
	cout << mioRettangolo.area() << endl;
	cout << mioTriangolo.area() << endl;

	getchar();
}
12
6


E fin qui ci siamo.

Proviamo a usare un puntatore:
#include "iostream"
using namespace std;

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

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

void main(){
	Rettangolo mioRettangolo(3,4);
	Triangolo mioTriangolo(3,4);
	Rettangolo *pRect=&mioRettangolo;
	Triangolo *pTriang = &mioTriangolo;
	cout << pRect->area() << endl;
	cout << pTriang->area()<< endl;

	getchar();
}
12
6


Funziona ancora, perché ho creato un puntatore di tipo Rettangolo alla classe base e uno di tipo Triangolo alla classe derivata.
Ma proviamo a creare due puntatori di tipo Rettangolo per ambedue le classi:
#include "iostream"
using namespace std;

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

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

void main(){
	Rettangolo mioRettangolo(3,4);
	Triangolo mioTriangolo(3,4);
	Rettangolo *pRect=&mioRettangolo;
	Rettangolo *pTriang = &mioTriangolo;
	cout << pRect->area() << endl;
	cout << pTriang->area() << endl;

	getchar();
}
Ecco, adesso invece è:
12
12


Se il puntatore è del tipo della classe base, quando viene chiamato il metodo viene eseguito quello della classe base, come se la classe derivata fosse un rettangolo.
Provo con valori diversi di base e altezza per spiegarmelo meglio.
void main(){
	Rettangolo mioRettangolo(3,4);
	Triangolo mioTriangolo(2,3);
	Rettangolo *pRect=&mioRettangolo;
	Rettangolo *pTriang = &mioTriangolo;
	cout << pRect->area() << endl;
	cout << pTriang->area() << endl;

	getchar();
}
12
6


Ecco: base e altezza forniti al costruttore della classe derivata sono 2 e 3, e l'area calcolata è 6, come se si trattasse di un rettangolo, non di un triangolo.

Quindi il problema è solo quando si usi un puntatore alla classe base. Usando un puntatore alla classe base, si può far comportare l'oggetto della classe derivata come un oggetto della classe base.

Il costruttore predefinito nella creazione di classi derivate

Ecco, adesso per continuare a ripassare le funzioni virtuali provo a istanziare la classe base Poligono, e mi trovo di fronte a un nuovo problema:
#include "iostream"
using namespace std;

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

};

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

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


void main(){
 Rettangolo mioRettangolo(3,4);

 Triangolo mioTriangolo(3,4);

 Poligono mioPoligono(3,4);

 cout << mioRettangolo.area() << endl;
 cout << mioTriangolo.area() << endl;
 cout << mioPoligono.area() << endl;
 getchar();
}
1>------ Inizio compilazione: Progetto: test1, Configurazione: Debug Win32 ------
1>  foglio.cpp
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(20): error C2512: 'Poligono': non è disponibile alcun costruttore predefinito appropriato
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(31): error C2512: 'Poligono': non è disponibile alcun costruttore predefinito appropriato
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(49): error C2065: 'mioPoligono': identificatore non dichiarato
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(49): error C2228: l'elemento a sinistra di '.area' deve avere una classe, struttura o unione
1>          il tipo è ''unknown-type''
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========
Ecco: non è disponibile alcun costruttore predefinito appropriato. Manca il costruttore di default della classe base, che nel momento in cui io creo un altro costruttore non viene più sottinteso ma deve essere esplicitamente dichiarato.

Ovvio all'errore:
#include "iostream"
using namespace std;

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

};

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

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


void main(){
 Rettangolo mioRettangolo(3,4);

 Triangolo mioTriangolo(3,4);

        Poligono mioPoligono(3,4);
 cout << mioRettangolo.area() << endl;
 cout << mioTriangolo.area() << endl;
 cout << mioPoligono.area() << endl;
 getchar();
}
E proviamo di nuovo:
12
6
0


Ripasso delle funzioni virtuali in C++

Ecco la funzione virtuale!

Mi sono chiesto "ma perché bisogna ripetere ogni volta il codice del metodo, se il nome del metodo è uguale, nella dichiarazione delle diverse classi derivate?
E ho trovato le funzioni virtuali: mettere nella dichiarazione della classe base il metodo come virtuale per poi ridefinire il metodo nella dichiarazione delle classi derivate.
Ma, ripensandoci bene, dov'è il vantaggio, se bisogna comunque riscrivere sempre il codice del metodo nella dichiarazione della classe derivata, da sostituire alla dichiarazione della funzione virtuale?

La differenza sta nel fatto che si può usare un puntatore del tipo della classe base per ogni classe derivata, e tramite il puntatore si può fare riferimento alla funzione virtuale, ma solo se questa è dichiarata nella classe base.
#include "iostream"
using namespace std;

class Poligono{
protected:
 int base,altezza;
public:
 virtual int area(){
  return 0;
 }

};

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

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


void main(){
 Rettangolo mioRettangolo(3,4);

 Triangolo mioTriangolo(3,4);

 Poligono * figura1 = &mioRettangolo;
 Poligono * figura2 = &mioTriangolo;

 cout << figura1->area() <<endl;
 cout << figura2->area() << endl;
 getchar();
}

Ma ora ho un dubbio: se la funzione, il metodo, non fosse dichiarato virtual non sarebbe la stessa cosa?

Proviamo subito a dichiarare il metodo non virtuale. Anche i metodi non virtuali possono essere ridefiniti nelle classi derivate, dunque che differenza c'è?

#include "iostream"
using namespace std;

class Poligono{
protected:
 int base,altezza;
public:
 int area(){
  return 0;
 }

};

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

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


void main(){
 Rettangolo mioRettangolo(3,4);

 Triangolo mioTriangolo(3,4);

 Poligono * figura1 = &mioRettangolo;
 Poligono * figura2 = &mioTriangolo;

 cout << figura1->area() <<endl;
 cout << figura2->area() << endl;
 getchar();
}
E vediamo l'output:
0
0


Ecco: invece, rendendo di nuovo la funzione virtuale:
#include "iostream"
using namespace std;

class Poligono{
protected:
 int base,altezza;
public:
 virtual int area(){
  return 0;
 }

};

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

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


void main(){
 Rettangolo mioRettangolo(3,4);

 Triangolo mioTriangolo(3,4);

 Poligono * figura1 = &mioRettangolo;
 Poligono * figura2 = &mioTriangolo;

 cout << figura1->area() <<endl;
 cout << figura2->area() << endl;
 getchar();
}
12
6


Se la funzione non è virtuale, il puntatore fa riferimento alla funzione della classe base, che restituisce zero. Se la funzione della classe base è virtuale, invece, fa riferimento alla funzione della classe derivata.

Ripasso ereditarietà in C++

Creiamo una classe poligono dalla quale ereditino il rettangolo e il triangolo...

#include "iostream"
using namespace std;

class Poligono{
protected:
 int base,altezza;
};

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

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


void main(){
 Rettangolo mioRettangolo(3,4);
 cout << mioRettangolo.area() <<endl;
 Triangolo mioTriangolo(3,4);
 cout << mioTriangolo.area() << endl;
 getchar();
}                        
Ho dovuto mettere protected i due membri base e altezza, altrimenti non sarebbero stati visti dalle classi derivate.
Ho dovuto creare per ogni classe derivata il suo costruttore, che non viene ereditato.
Per ogni classe derivata ho dovuto reintrodurre il metodo area(), con una sintassi diversa a seconda della figura geometrica.

martedì 8 luglio 2014

Ripasso delle classi in C++ (già lo sapevo ma è tanto tempo...)

Ripassiamo un po' i costruttori...

Classe Rettangolo, come da classico esempio.
Larghezza e altezza sono private.
Viene dato un valore dal costruttore. Mettiamo nel contesto della classe solo i... come si chiamano, prototipi?
Sì, prototipi.
Seguono le definizioni all'esterno del corpo della classe, mediante l'operatore di scope.
#include "iostream"
using namespace std;

class Rettangolo{
 int base,altezza;
public:
 Rettangolo(int,int);
 int area();
};

Rettangolo::Rettangolo(int b, int a){
 base=b;
 altezza=a;
}

int Rettangolo::area(){
 return base*altezza;
}
Adesso istanziamo la classe.
#include "iostream"
using namespace std;

class Rettangolo{
 int base,altezza;
public:
 Rettangolo(int,int);
 int area();
};

Rettangolo::Rettangolo(int b, int a){
 base=b;
 altezza=a;
}

int Rettangolo::area(){
 return base*altezza;
}
void main(){
 Rettangolo mioRettangolo(3,4);
 cout << mioRettangolo.area() <<endl;
 getchar();
}

Ecco!
12


Fatto!

Variabili statiche in C++

Esercitiamoci con le variabili statiche in C++...

Ecco: una volta che ho inizializzato una variabile, questa rimane statica e non si può inizializzare un'altra volta.
Perché, forse in genere le variabili si possono inizializzare più volte?
Vediamo...

#include "iostream"
using namespace std;


void main(){
 for(int n=0;n<4;n++){
  int variabile=0;
  variabile++;
 }
 
}
Questo codice non dà alcun messaggio di errore: mi è sembrato strano dal momento che una variabile viene dichiarata più volte nell'ambito di un loop.
Ecco la risposta: http://bytes.com/topic/c/answers/727941-redefinition-inside-loop

Ossia la variabile, dichiarata a ogni ciclo, cessa il suo scope con il terminare del singolo ciclo.
Infatti una volta terminato il loop il nome della variabile non viene riconosciuto e questo codice dà errore:
#include "iostream"
using namespace std;


void main(){
 for(int n=0;n<4;n++){
  int variabile=0;
  variabile++;
 }
 cout << variabile;
}

1>------ Inizio compilazione: Progetto: test1, Configurazione: Debug Win32 ------
1>  foglio.cpp
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(10): error C2065: 'variabile': identificatore non dichiarato
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========

Per ovviare, dichiaro una variabile prima:
#include "iostream"
using namespace std;

int numero;
void main(){
 for(int n=0;n<4;n++){
  int variabile=0;
  variabile++;
  numero=variabile;
 }
 cout << numero;
        getchar();
}
questo codice non mi dà errore.
E vediamone l'output:
1

Adesso faccio il colpo da maestro, e dichiaro static questa variabile:
#include "iostream"
using namespace std;

int numero;
void main(){
 for(int n=0;n<4;n++){
  static int variabile=0;
  variabile++;
  numero=variabile;
 }
 cout << numero;
 getchar();
}
4

Ecco! A ogni ciclo la variabile viene reinizializzata riprendendo però l'ultimo valore che aveva.
Continua a non essere presente al di fuori del suo scope del singolo ciclo, infatti questo codice mi dà sempre errore di identificatore non dichiarato.
#include "iostream"
using namespace std;

int numero;
void main(){
 for(int n=0;n<4;n++){
  static int variabile=0;
  variabile++;
  numero=variabile;
 }
 cout << variabile;
 getchar();
}
1>------ Inizio compilazione: Progetto: test1, Configurazione: Debug Win32 ------
1>  foglio.cpp
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(11): error C2065: 'variabile': identificatore non dichiarato
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========

lunedì 7 luglio 2014

metodo statico in C++

E ora ripassiamo parallelamente un po' di sintassi C++

#include 

void main(){
 printf("%s", "Ciao, fesso");
 getchar();
}
Ciao, fesso




Dopo questo esercizietto per riprendere confidenza con la funzione printf della libreria cstdio.h, ripassiamo come si "fanno" le classi...
#include 


class Classe{
public:
 void metodo(){
  printf("%s","Ciao Stupido");
                getchar();
 }
};




void main(){
 printf("%s", "Ciao, fesso");
 getchar();
}
Ciao, fesso



E adesso proviamo a chiamare il metodo della classe...
#include 


class Classe{
public:
     static void metodo(){
  printf("%s","Ciao Stupido");
  getchar();
 }
};




void main(){
 Classe miaClasse;
 miaClasse.metodo();
}
Ho dovuto farlo dopo aver istanziato la classe; però: senza istanziare la classe ottengo messaggi di errore, nonostante il metodo sia statico.
Questa è una differenza con il C# e il Java...

Primi passi col C#

Bene.
Creiamo una classe.

public class AltraClasse
{
    public static void metodo()
    {
        System.Console.WriteLine("Fesso");
        System.Console.ReadLine();
    }
}
public class HelloWorld
{
    public static void Main()
    {
        System.Console.WriteLine("Ciao mondo crudele");
        System.Console.ReadLine();
    }
}
Ecco l'output:
Ciao mondo crudele


Ambedue le classi hanno un metodo static, ma è quello che si chiama Main che viene eseguito inizialmente.


Adesso faccio in modo che Main chiami il metodo dell'altra classe:
public class AltraClasse
{
    public static void metodo()
    {
        System.Console.WriteLine("Fesso");
        System.Console.ReadLine();
    }
}
public class HelloWorld
{
    public static void Main()
    {
        AltraClasse.metodo();
    }
}
Ecco:
Fesso



Ora, però, provo a dichiarare non static il metodo dell'altra classe.
public class AltraClasse
{
    public void metodo()
    {
        System.Console.WriteLine("Fesso");
        System.Console.ReadLine();
    }
}
public class HelloWorld
{
    public static void Main()
    {
        AltraClasse.metodo();
    }
}
E già dopo aver scritto il codice, l'IDE mi dà un segnale di errore:


Questo perché non essendo il metodo static è necessario istanziare la classe.

Proviamo a istanziare la classe:
public class AltraClasse
{
    public void metodo()
    {
        System.Console.WriteLine("Fesso");
        System.Console.ReadLine();
    }
}
public class HelloWorld
{
    public static void Main()
    {
        AltraClasse Altra=new AltraClasse();
        Altra.metodo();
    }
}
E adesso è tutto OK:
Fesso