Sei sulla pagina 1di 21

Spesso quando si vuole iniziare con un linguaggio di programmazione sorgono mille dubbi relativi al fatto che uno sia

meglio di un altro e questo anche per quanto riguarda i sistemi di sviluppo.

Visual C++ vs. C++Builder


di Flavio Bernardotti Livello: Principiante

Introduzione
Tanti anni fa la vita era molto pi semplice in quanto la scelta non era affatto possibile e quindi lunica soluzione era quella di prendere quello che passava il convento. In ogni caso gi dai primi anni della comparsa del C/C++ come linguaggio di programmazione disponibile su piattaforme PC si era presentato il problema se andare verso lambiente di mamma Microsoft oppure verso quello di Borland, sempre molto pi disponibile nei confronti di quello che era lambiente per lo studente, sia per fattori di prezzi che per questioni di filosofie molto pi legate agli smanettoni. Philip Khan di fatto giungeva dagli ambienti universitari e quindi come ottica, quella di fatto adottata anche per Turbo Pascal, era sicuramente pi simile a quella dello sviluppatore autodidatta. Gli anni sono passati e gli ambienti si sono evoluti tanto da fare diventare i linguaggi come cose secondarie rispetto a quello che sono gli insiemi che compongono il panorama dellinformatica. Cosa significa questo ? Prendiamo lesempio, per fare capire questaffermazione, di un mio caso personale legato allo sviluppo del pacchetto indirizzato alla gestione della rete FidoNet denominato Italink interamente scritto in Linguaggio C nel 1986. Il pacchetto gestiva diverse problematiche come ad esempio un interprete di linguaggio che permetteva di creare delle presentazioni dinamiche allinterno delle schermate iniziali che venivano proposte alle persone ch4e si collegavano al BBS, un editor uguale al vecchio WordStar che permetteva lediting dei testi dei messaggi, un interprete di database compatibile con Dbase III che gestiva le sezioni legate alla gestione delle basi di dati, un certo numero di protocolli di comunicazione per i trasferimenti binari di files e altri problemi, comunque interamente gestiti allinterno del pacchetto. A quei tempi esisteva il sistema operativo MsDos il quale era una base povera sualla quale era possibile sviluppare del software. Le librerie scarseggiavano e quindi la risoluzione dei problemi legati allo sviluppo degli algoritmi interni era compito esclusivo del programmatore. In altre parole visto che il sistema operativo non offriva nessuna funzione particolare, lo sviluppo di queste era compito esclusivo del programmatore il quale partendo da algoritmi puramente astratti e con il solo linguaggio doveva creare tutto il patrimonio funzionale del programma. I tempi sono cambiati ed in particolar modo i sistemi operativi si sono sviluppati allinverosimile implementando sugli stessi anche una serie di servers i quali sono stati progettati per la gestione di compiti particolari indirizzati ad offrire servizi anche molto complessi utilizzabili dai programmatori per la creazione di sistemi software. Le complicazioni concettuali si sono ampliate e quindi di conseguenza anche le metodologie di analisi hanno dovuto seguire la stessa evoluzione al fine di permettere al soluzione di queste. Chiaramente lo stesso processo lhanno dovuto subire i linguaggi che si appoggiano su queste filosofie analitiche. Uno di questi casi la programmazione object oriented. Chiaramente il numero e la complessit dei concetti si sono moltiplicati per cui spesso questo diventa un punto a discapito di chi inizia il quale ha sempre maggiormente le idee confuse non sapendo quasi mai quali scelte fare. Per poter analizzare le differenze tra i due sistemi di sviluppo della Microsoft e 1quello della Borland si deve avere ben presente quella che la filosofia di programmazione object oriented. Per fare questo faremo un piccolo riassunto sui punti fondamentali. Chiaramente non vuole essere un corso di programmazione di questo tipo rimandando a volumi pi completi questo compito.

La dichiarazione della variabili


Nei testi da me scritti ho sempre differenziato le fasi della programmazione indicando con quella dichiarativa la fase in cui il programmatore osserva il mondo che deve riprodurre individuando i dati, o informazioni, e le

sue tipologie dallaltra fase, quella algoritmica, in cui si definiscono le operazioni che successivamente devono essere fatte Dichiarare una variabile significa osservare un oggetto che sia numerico o semplicemente una sequenza di caratteri e valutare quanto spazio questa tiene in memoria riservando quindi un numero di bytes sufficienti ed etichettando questo spazio con una label stringata che ci servir a riferirsi a questa. Quindi dopo la dichiarazione avremo uno spazio in memoria utile per memorizzarci dei valori. Ma quali valori ? I valori relativi a parametri dei problemi che stiamo riproducendo. Se dovessimo riprodurre un semplice calcolo di un area di un rettangolo, i valori saranno quelli relativi ai due lati. La programmazione strutturata aveva aggiunto un concetto aggiuntivo che permetteva di incapsulare dentro ad un contenitore astratto variabili relativi ad un determinato insieme. E di fatto la struttura pu essere paragonata al contenitore di un insieme matematico. Nellesempio precedente abbiamo detto che per calcolare larea di un rettangolo dobbiamo avere le due variabili relative ai due lati. In linguaggio C avremmo : int int lato1; lato2;

Se con il concetto di struttura volessimo creare un nuovo tipo mediante il quale poter dichiarare altre variabili legate alla rappresentazione dello stesso tipo di oggetto potremmo fare : struct rettangolo { int lato1; int lato2; }; e successivamente utilizzare la struttura per dichiarare delle variabili ciascuna delle quali avrebbe i suoi membri interni distaccati e indipendenti dagli altri. Ad esempio : struct rettangolo rett1; struct rettangolo rett2; rett1.lato1 = 25; rett1.lato2 = 45; rett2.lato1 = 1; rett2.lato2 = 34; Nel caso della struttura i membri interni sono variabili normalissime. Se avessimo allocato due variabili indipendenti, come quelle dichiarate nella struttura, in memoria avremmo riservato 2 bytes per ciascuna e quindi avremmo avuto : 00400001 00400002 00400003 00400004 00400005 00400006 00400007 00400008 Byte 1 Byte 2 Byte 3 Byte 4 Byte 1 Byte 2 Byte 3 Byte 4 Lato1 Lato2 Lato1 Lato2 Rett1 Rett2

Dobbiamo sempre ricordarci che luso delle strutture pretende due fasi separate che al limite in fase operativa possono anche coincidere e precisamente la fase legata alla definizione e quella invece della dichiarazione. Ricordiamoci sempre che dichiarare una variabile che sia un intero o che sia una struttura significa fondamentalmente riservare in memoria un cero numero di bytes il cui indirizzo di partenza il compilatore lo abbina al nome della variabile.

La fase della definizione specifica solo i membri della struttura ma di fatto non riserva per questa nessuno spazio in memoria. Successivamente la dichiarazione di una variabile relativa ad una certa struttura permette al sistema di allocare in memoria un spazio che in pratica grande quanto la somma delle dimensioni dei membri di questa. Limmagine di prima dava lidea a livello di memoria di come di fatto viene allocata una struttura. Luso della struttura permette di utilizzare le facilitazioni del linguaggio per accedere ai suoi membri. Dicevamo prima che le due fasi legata alla creazione di una struttura possono anche coincidere. In altre parole potremmo fare : struct rettangolo { int lato1; int lato2; }; struct rettangolo rett1; oppure avremmo potuto fare coincidere i due passi con : struct rettangolo { int lato1; int lato2; } rett1; Per accedere ai vari mebri quindi avremmo potuto fare : rett1.lato1 = 25; Conoscendo un bricciolo di aritmetica degli indirizzi avremmo anche potuto fare nel seguente modo. Vi dir passo a passo quello che significa la cosa che scrivo : rett1 rett1 una variabile ce rappresenta una struttura di tipo rettangolo per cui questa sar allocata da qualche parte della memoria e occuper 2 bytes. In pratica usando loperatore che indica lindirizzo di potremmo avere : &rett1 per dire lindirizzo di dove si trova rett1. Quindi il primo membro, il primo intero, coincider con questindirizzo mentre il secondo intero si trover a questindirizzo pi due bytes. Quindi &rett1 lindirizzo di una struttura ma convertito con : (int *) &rett1 sar come dire che quellindirizzo forzato a essere visto cme se fosse lindirizzo di un numero intero. Se a questo aggiungiamo le dimsnioni di un altro intero con : ((int *) &rett1) + 1 avremo puntato allindirizzo di dove si trova il secondo intero. Quindi usando loperatore che dice il contenuto o loggetto puntato da : *(((int *) &rett1)+1) acederemo al contenuto di quel numero. Quindi fare : *(((int *) &rett1)+1) = 25; sar come fare :

rett1.lato1 = 25; La programmazione object oriented ha inserito nuovi concetti al fine di riuscire a rappresentare e incapsulare i nuovi oggetti contemplati da questa nuova filosofia (nuova relativamente). Un estensione del concetto di struttura quello della classe. Questa di fatto una struttura in cui, a parte le variabili, possibile definire anche i metodi utilizzati per la gestione degli oggetti. La struttura di prima potrebbe essere tramutata in classe con : class rettangolo { int lato1; int lato2; int calcolaArea() };

{ return(lato1 * lato2); };

Vedete che in questo caso non sono presenti solo le variabili ma anche un metodo indirizzato a calcolare larea del rettangolo che la classe rappresenta. Chiaramente la classe non il sinonimo di oggetto in quanto questultimo di fatto pu essere un insieme di classi. La programmazione object oriented di fatto contempla anche diverse metodologie idonee a permettere lapplicazione di concetti come ad esempio quello dellereditariet. In pratica questa permette di fare derivare una classe da un'altra e quindi fa in modo che la classe creata possa di fatto accedere ai parametri di questa e usare i suoi metodi come se di fatto fossero suoi. Volendo fare un discorso metaforico potremmo dire che qualsiasi cosa del nostro mondo pu essere vista come un oggetto che a sua volta composto da altri oggetti ciascuno dei quali possiede determinate caratteristiche e modi di funzionamento. Avevamo detto prima che volevamo ricordarci a cosa si riferivano determinati dati potevamo utilizzare il concetto di struttura per incapsulare tutte le variabili relative ad un determinato oggetto. Nel Linguaggio C++ il concetto di classe un ampliamento di quello di struttura ovvero un contenitore idoneo a contenere sia i dati che i metodi di funzionamento relativi a un qualche cosa. Non ho usato il termine oggetto in quanto verrebbe se no da pensare che quelli definiti con il termine di oggetti siano di fatto le classi del C++. Ritornando al discorso dellanalisi possiamo dire che ogni problema o che ogni componente del mondo reale pu essere scomposto in un certo numero di sottocomponenti. Anche nellambito della programmazione ci ritroviamo a poter utilizzare i concetti di struttura e di classe per descrivere questi componenti. Facciamo un esempio pratico. Supponiamo di dover creare un insieme di oggetti idonei a ricevere in input dei dati da tastiera ed a stampare delle stringhe statiche. Analizzando tutti e due i componenti ci accorgiamo che questi sono disegnati a video e qui rappresentati da dei rettangoli. Questi rettangoli servono a visualizzare le dimensioni di tali oggetti nellambito dellinterfaccia utente. Quindi indipendentemente dal fatto che poi dentro a questi rettangoli si scriva o si leggano i tasti digitati, i metodi per il disegno dei bordo sar comune. Ora prendiamo in esame un sistema che gestisca il disegno di rettangoli a video. Come propriet memorizzabili in variabili ci saranno quelle delle posizioni di x e y e della larghezza e altezza. A livello di metodi funzionali invece ci sar una funzione che sfruttando questi dati esegue il disegno del rettangolo. Volendo incapsulare tutti gli appartenenti a questo blocco potremmo usare la definizione di classe con : class rectangle { int x, y; int width, height ; }; Volendo inserire anche il metodo di disegno la classe si tramuterebbe in : class rectangle { int x, y; int width, height ; void designRect(); };

Ora la classe rettangolo pu essere usata per creare un oggetto rettangolo il quale possiede tutto quello che gli necessita per il suo ciclo vitale e funzionale, semplicemente dichiarando delle variabili con questo tipo. Potremmo quindi fare : class rectangle rect1; Quindi potremo prima assegnare le variabili con : rect1.x = 23; rect1.designRect(); E inutile dire che sicuramente la funzione designRect() utilizzer i suoi dati interni alla classe per lesecuzione del disegno del rettangolo. Ora se dovessimo continuare la creazione degli oggetti di cui avevamo parlato potremmo fare una cosa. Una delle caratteristiche della programmazione object oriented legata al concetto di ereditariet. In pratica creando altre classi si potrebbe usare questa appena definita per fare nascere la nuova classe. Sicuramente sia la classe dinput che quella per la gestione della stringa statica a video dovr utilizzare una funzione per disegnare il rettangolo che delimita il bordo del campo. Invece di scrivere internamente tale funzione potremo creare la nuova classe in modo che erediti tale funzionalit dalla classe rectangle. class { }; Allo stesso modo potremo definire la classe : class { staticField : public rectangle char stringa[256]; staticField(char *value); void printValue(); }; Ereditando dalla classe rectangle la funzione per il disegno del bordo si potr fare : editField field1; editField : public rectangle char valore[256]; void leggiValore();

field1.x = 23; field.designRect(); In questo caso ho usato la funzione ereditata per farvi vedere che ereditandola la si pu utilizzare ma sicuramente questa verrebbe usata da qualche funzione interna alla classe che disegner il bordo al momento della creazione delloggetto editField. Questo un esempio molto generico in quanto poi vedremo che dentro alle classi esistono degli attributi che permetterebbero di definire come privati certi membri, pubblici altri ecc. Quello che mi interessava era quello di far capire come possibile sfruttare il concetto di ereditariet ovvero quando un classe creata a partire da un'altra eredita tutte le funzioni incluse in questa o in quelle da cui a sua volta questultima classe deriva. Nella teoria delle classi esistono due concetti particolari ovvero quelli del costruttore e quello del distruttore. In pratica questi due sono due metodi che vengono richiamati, se implementati nella classe, allatto della creazione della classe e allatto della sua distruzione ovvero nellistante in cui viene richiesta la disallocazione. Avevamo visto prima che grazie al concetto di puntatore era possibile utilizzare lallocazione dinamica ovvero quel tipo in cui si richiede al sistema, tramite una funzione, di allocare una certa quantit di memoria e quindi di assegnare lindirizzo di partenza al puntatore di destinazione. La programmazione Object Oriented include un nuovo operatore che permette di creare dinamicamente degli oggetti.

Stiamo parlando delloperatore new. Invece di richiedere lallocazione statica di una classe, ad esempio con : className Potremmo fare : className *varName = new className; varName;

Il sistema richiederebbe al sistema operativo di allocare da qualche parte della memoria di grandezza sufficiente e assegnerebbe lindirizzo al puntatore. Allatto della creazione, se gestito allinterno della classe, verrebbe richiamato il costruttore della classe che a livello di dichiarazione in genere come un metodo che possiede lo stesso nome della classe. Ad esempio : class }; className() il metodo costruttore, che come abbiamo apena detto verrebbe richiamato in fase di creazione della classe. Il secondo metodo invece, quello preceduto da ~ il distruttore ovvero il metodo richiamato in fase di distruzione della classe. La creazione dinamicamente si ottiene con new. La distruzione di una classe avviene quando non ha pi scopo oppure quando viene richiesta la distruzione tramite loperatore delete. #include <iostream> using namespace std; class Box { public: double length; double breadth; double height; // Class definition at global scope // Length of a box in inches // Breadth of a box in inches // Height of a box in inches className { className(); ~className();

// Constructor definition Box(double lv, double bv, double hv) { cout << endl << "Constructor called."; length = lv; // Set values of breadth = bv; // data members height = hv; } // Function to calculate the volume of a box double Volume() { return length * breadth * height; }

};

int main(void) { Box Box1(78.0,24.0,18.0); Box CigarBox(8.0,5.0,1.0); double volume = 0.0; volume = Box1.Volume();

// // // //

Declare and initialize Box1 Declare and initialize CigarBox Store the volume of a box here Calculate volume of Box1

cout << endl << "Volume of Box1 = " << volume;

cout << << << cout << }

endl "Volume of CigarBox = " CigarBox.Volume(); endl;

return 0; Parlavamo prima dicendo che con il compilatore C vengono distribuite delle librerie contenenti un numero molto elevato di funzioni destinate allo svolgimento dei compiti pi diversi. La distribuzione di Windows ha portato a implementare con il compilatore un'altra serie enorme di librerie di funzioni ciascuna delle quali destinata al controllo di windows stesso, come ad esempio il controllo delle finestre, delle dialog, dei campi di edit ecc. Lavvento del C++ ha portato alla creazione di classi che incapsulano tutte queste API allinterno di quelle che sono state chiamate con il nome di Microsoft Foundation Class (MFC). Scrivendo un programma in C normale potremo, al fine di gestire le varie caratteristiche del programma utilizzare la API oppure, usando il C++ implementeremo il tutto sfruttando le classi MFC. Chiaramente il concetto di classe ha permesso di implementare tutte le funzioni a partire da dei semplici oggetti di base. Andando a vedere la carta gerarchica delle classi incluse dentro a MFC ci accorgeremmo che tutte derivano dalla classe CObjetc. Il pericolo di usare il C++ venendo dal C potrebbe essere quello che avevo fatto io ai tempi in cui avevo fatto il passaggio da uno allaltro, verso il 1987. Quando scrivete un programma con la metodologia object oriented cercate di identificare ogni singolo componente del programma osservandolo bene e cercando di definirlo con tutte le sue variabili e con tutti i suoi metodi necessari a farlo funzionare. Se loggetto lo avrete strutturato bene questo potrebbe essere preso e spostato in un altro ambito continuando a vivere tranquillamente e quindi funzionare. In pratica dicevo che quando nel 1987 ho comprato la prima versione di compilatore C++, lo Zortech, continuai a scrivere tranquillamente codice in C utilizzando le classi in alcuni punti ma senza che poiu alla fine il programma risultasse un'unica classe. In altre parole pi che scrivere in C++ scrivevo programmi in C orientati al C++. Un giorno acquistai C++View che altro non era che una trasposizione dello Smaltalk verso il C++. Questo sistema di sviluppo non ti lasciava uscire dalle classi per cui diventava necessario andare a vedere i singoli componenti di base e mano mano permetteva di creare nuove classi ma sempre partendo da quelle gi esistenti. Alla fine del tutto il programma era una classe che aveva ereditato gerarchicamente tutte le altre classi. Guardate la tabella di cui vi ho parlato, quella della struttura delle classi MFC, e capirete quello che voglio dire. Daltra parte, come abbiamo gi detto, Windows costituisce lambiente idoneo allincapsulamento di tutte le componenti sia che questi siano relativi alla gestione dellinterfaccia utente, che per quanto riguarda le gestioni delle basi di dati .

Le classi e il mondo di Visual Studio e C++Builder


Chiaramente come avevamo detto inizialmente questo non voleva essere un vlume sulla programmazione object oriented specifico ma solo mostrare le differenze a livello di progettazione software utilizzando I due pacchetti di Microsoft e di Borland. Abbiamo detto che in origina Microsoft ha fatto uscire tutte le funzioni per la programmazione in ambiente Windows in quelle che erano definite come API del sistema operativo. Queste servivano a creare le finestre, le dialog, gli oggetti sui forms ecc. Chiaramente la programmazione object oriented ha fornito un sistema ottimale per incapsulare tutte le funzionalit di questo enorme sistema operativo. La classi MFC infatti includono, strutturate in modo gerarchico, tutti gli oggetti presenti in ambiente Windows. Ad esempio quando creiamo una dialog e ci mettiamo su un pulsante questo verr rappresentato da una classe CButton la quale ci permetter di usare una variabile per riferici a quel pulsante specifico e quindi di utilizzare i suoi metodi e le sue propriet per modificarne lo stato, le apparenze e per gestirlo come ad esempio intercettare gli eventi come quello legato al push. In alcuni casi la creazione delle classi legate agli oggetti posizionati su una dialog viene fatto in automatico del sistema di sviluppo, mentre altre volte allinterno dei nostri programmi dovremmo pensarci noi a allocare le variabili. Portiamo come esempio la creazione di una dialog.

Quando richiediamo di crearne una nuova il sistema di wizard ci domanda come vogliamo chiamare la classe che rappresenter la dialog. Successivamente in modo visuale metteremo su questa i campi, le labels, i pulsanti ecc. Quando allinterno del nostro programma vorremo visualizzare una dialog di quel tipo dovremo dichiarare un variabile di quella classe che abbiamo creato allatto della creazione della dialog. Ad esempio se la classe si chiamava CdialogClienti potremo fare : CdialogClienti dlg1; Chiaramente inserire degli oggetti su una dialog deve darci anche la possibilit di gestirli mediante funzioni che ci permettano, al minimo, di leggere i valori, di cambiargli gli attributi e questo il wizard di Visual Studio ce lo permette grazie alla possibilit di creare variabili che serviranno per riferirci a questi. Queste funzioni il sistema legato a Visual Studio lo fa tramite dei sistemi di mappatura Vediamo praticamente la cosa. Supponiamo di dover creare e gestire una dialog in cui inserire dei dati relativi ad un anagrafica clienti. Per prima cosa nellambito di un nuovo progetto accediamo alla finestra in cui sono gestite le risorse. In questa selezioniamo la voce dialog e specifichiamo di voler inserirne una nuova.

<Titolo del paragrafo>


<Contenuto del paragrafo.>

A questo punto sul workspace ci verr visualizzata la dialog vuota. A livello di codice non abbiamo ancora nessun riferimento a questa ne con una classe ne con nessuna altro oggetto del cpp. La creazione della classe verr eseguita nellistante in cui selezioneremo la voce Class Wizard nel menu POPUP che compare premendo con il tasto destro del mouse sul foglio di lavoro.

<Titolo del paragrafo>


<Contenuto del paragrafo.>

Conclusioni
<Conclusioni dell'articolo.>

Bibliografia
A questo punto ci verr richiesto il nome d assegnare alla classe. Questa classe ci permetter di creare allinterno del programma dei riferimenti a questo tipo dia dialog. Dandogli il nome CCustomerDlg potremo usare questa per creare sia staticamente che dinamicamente delle variabili legate a questa. Ad esempio sara possibile fare staticamente : CCustomerDlg dlg1; oppure dinamicamente :

CCustomerDlg *dlg1; dlg1 = new CCustomerDlg(); In C++Builder la gestione dellinterfaccia utente si esegue con il concetto di FORM, anche se di fatto potrebbe gestire benissimo anche il modello classico a dialog. In ogni caso questo sistema di sviluppo possiede una logica sua per cui se si intende utilizzarlo conviene attenersi a questa. Quando viene richiesta la creazione di una nuova FORM C++Builder crea automaticamente una classe che la rappresenta. In Visual C++ una volta creata a video la dialog e assegnato un nome alla classe, per visualizzare la dialog sar necessario allocare staticamente o dinamicamente delle variabili e usare i metodi interni alla classe stessa come ad esempio quello DoModal(). Per visualizzare a video una dialog dovremo fare in qualche punto del programma : CCustomerDlg dlg1; dlg1.DoModal(); C++Builder utilizza il nome assegnato al form nellapposito campo Name dellinspector, ovvero della finestra che compare sul lato sinistro del video premendo F11, per assegnare il nome alla classe. C++Builder utilizza uno strano metodo di gestione che per certi versi abbastanza comodo. Come abbiamo appena visto con Visual Studio, per visualizzare una dialog dobbiamo definire una variabile di quella classe e usare il metodo DoModal() per visualizzarla a video. Ad esempio potremmo mettere nellevento di gestione di un opzione di menu il codice appena descritto. In questo caso quando lutente selezioner la voce di menu la dialog sar visualizzata a video. C++Builder invece crea automaticamente la classe e quando il programma viene lanciato i form creati vengono automaticamente creati ma mantenuti NON VISIBILI ovvero con lattributo Visibile di quella classe a FALSE.

Premendo F12 sul FORM passiamo alla visualizzazione del codice in cui potremo vedere i dati della classe. class TCDialogDlg : public TForm { __published: // IDE-managed Components private: // User declarations public: // User declarations __fastcall TCDialogDlg(TComponent* Owner); }; //--------------------------------------------------------------------------extern PACKAGE TCDialogDlg *CDialogDlg; Come potete vedere il programma ha creato un riferimento *CdialogDlg automaticamente. Questo verr creato allatto del lancio del programma. Quando vorremo visualizzare il form sar sufficiente che facciamo : CdialogDlg->Visibile = TRUE;

La differenza quindi tra C++Builder e Visual Studio sta nel fatto che il primo crea automaticamente la classe e crea il form allattivazione del programma mentre il secondo crea la classe solo dopo nostra richiesta fatta con il Class Wizard e ci permette con questa di creare degli oggetti solo dopo che lo facciamo in modo esplicito. Ci sono dei pro e dei contro a tutte e due i metodi. Dal punto di vista della semplicit sicuramente il primo metodo pi immediato ma allo stesso tempo non sicuramente quello che cura maggiormente leconomia di memoria. Infatto C++Builder, se non vengono utilizzate procedure apposite, crea tutti i form automaticamente e li tiene nascosti. Chiaramente questo pretende meggiore memoria rispetto alla pratica di allocare e disallocare quando serve. Ora il discorso prosegue parlando degli oggetti che possiamo inserire nelle dialog. La dialog mantiene i dati dei suoi oggetti allinterno del file di risorse mentre C++Builder gestisce questi oggetti mediante le loro classi mediante allocazioni eseguite allatto della creazione delle form stesse. Visual Studio quando inseriamo un oggetto, ad esempio un campo dedit, crea un riferimento a questo attribuendogli un ID e memorizzandolo dentro al file risorse. Mediante funzioni del SDK di Windows possiamo eseguire funzioni di controllo su di questi come ad esempio modificare gli attributi, leggere e settare i valori contenuti e anche intercettare gli eventi che possono avvenire su di questi come ad esempio lacquisto e le perdita del focus. Le classi MFC che hanno incapsulato nel C++ gli oggetti contemplati dal SDK di Windows ha permesso di creare delle variabili di una certa classe. Ad esempio MFC contengono la classe CEdit, quella CButton e cosi via. Grazie al class wizard possiamo creare delle variabili che ci permetteranno di accedere ai metodi e alle risorse di quegli oggetti specifici. Supponiamo di voler posizionare sulla dialog creata dei campi statici in cui vengono specificati i prompt e dei campi di edit dove inserire determinati valori. I campi statici non ci interessa gestirli, a meno che non vogliamo poi durante lesecuzione modificarli come ad esempio per scriverli in un'altra lingua, e quindi una volta posizionati li lasciamo li. I campi di edit invece dovremo gestirli per ad esempio leggere i valori scritti dalutente.

Per fare questo dopo aver inserito sulla dialog i campi, creaiamo le variabili tramite il Class Wizard.

Una volta richieste le funzionalit di questo ci verr mostrata la finestra in cui vengono listati gli ID di tutti gli oggetti inseriti sulla dialog. Selezionandone uno e premendo Add Variable ci verr richiesto il nome che intendiamo assegnare a quella variabile e il tipo di questa. Questa tipologia sar in funzione della tipologia di servizio che vogliamo eseguire. Prendendo ad esempio un campo di edit potremmo leggere un valore oppure settare il fuoco su questo. Queste due funzionalit vengono eseguite da tipi diffrenti.

Ad esempio MFC utilizza un sistema di mappatura automatica di variabili del tipo che ci interessa leggere con il campo specifico. In altre parole se volessimo avere una variabile che contiene il valore del campo, dopo aver selezionato lID di un campo dedit potremo selezionare il tipo VALUE.

Visual Studio mapper qesta variabile con il campo per cui se volessimo leggere il valore potremo fare direttamente riferimento al nome della variabile. M_Valor1 Ho detto automaticamente anche se solo vero parzialmente. Esiste una funzione che aggiorna le variabili dichiarate con i valori contenuti nei campi. Supponiamo che dopo aver premetu un tasto ci interessi leggere il valore di un campo di edit. La funzione : UpdateData(TRUE) Legge i valori dai campi e li assegna alle varabili che abbiamo dichiarato. Questo Visual Studio lo esegue utilizzando una funzione che esegue questa mappatura e precisamente, in questo caso : void CCustmerDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CCustmerDlg) DDX_Text(pDX, IDC_EDIT2, m_Valor1); //}}AFX_DATA_MAP } Questa funzione viene gestita automaticamente per cui noi dovremo solo dichiarare le variabili che ci rappresenteranno i vari campi. Se invece vogliamo fare la funzione inversa ovvero inserire un valore dentr queste variabili e poi aggiornare i campi a video dovremo fare, ad esempio : m_Valor1 = Valore da inserire; UpdateData(FALSE); Chiaramente poi in base alla tipologia del campo questo conterr pi e meno attributi e metodi. Un campo di edit (CEdit) sicuramente pi semplice di un campo COMBO. Sempre dalla stessa dialog comparsa selezionando Class Wizard potremo anche gestire il collegamento degli oggetti con le funzioni che gestiscono gli eventi. Supponiamo di voler creare una nuova funzione che viene richiamata quando il campo perde il fuoco. Come potete vedere nelimmagine che segue nella finestrella a sinistra si seleziona lID del campo, in quella centrale levento che si intende gestire mentre con il pulsante si pu richiedere la creazione di una nuova funzione adatta a questa gestione.

Riassumendo possamo dire che con Visual Studio creiamo la dialog. Successivamente mediante il ClassWizard creiamo una classe con la quale potremo creare delle variabili che rappresentano la dialog. Sulla dialog inseriamo i campi, le scritte, le liste ecc. e per ciascuna di queste che vogliamo gestire creiamo, sempre con il ClassWizard, delle variabili di tipo idoneo. Queste variabili verranno utilizzate dentro al programma per gestire la lettura, la scrittura di valori dentro ai campi, linserimento dei valori nelle ListBox ecc. C++Builder invece usa sempre lo stesso automatismo utilizzato per la creazione della classe rappresentativa del FORM nellambito della creazione delle classi che permetteranno la gestione di questi oggetti allatto dellesecuzione del programma. Linspector dove sono visualizzate le informazioni degli oggetti possiedono tra questi anche il nome. Questo nome verr utilizzato per accedere alle propriet di questi oggetti. Mentre in Visual Studio dovremo richiedere esplicitamente la creazione di un oggetto, C++Builder crea automaticamente con il nome specificato allinterno dellattributo name.

Se nel programma volessimo leggere il valore del campo sara sufficiente leggere il valore Text allinterno della della variabile Edit1 o come abbiamo dato i nome alloggetto. Ad esempio : Edit1->Text = Nome da assegnare; C++Builder molto pi semplice di Visual Studio in quanto tutti gli attributi sono sempre visualizzati nella finestra dellinspector e comunque mentre scriviamo il nome della variabile allinterno delleditor del programma ci compare una finestrella che c visualizza le possibili scelte. Ad esempio se nella finestra a fianco vedete che esiste il campo Color allora questo sar anche accessibile da programma usando la variabile legata a questo campo.

Ad esempio per settare il colore del campo poremo fare : Edit1->Color = clRed; Abbiamo detto prima che C++Builder attiva allatto del lancio del programma tutti I form per cui anche se di fatto sono mantenuti non visibili, ovvero con lattributo Visibile a FALSE, questi di fatto sono presenti per cui mediante le variabili che rappresentano il FORM possibile accedere ai valori su questi contenuti anche da altre FORM. Supponiamo di essere su un FORM in cui visualizziamo i dati ricevuti tramite modem e supponiamo anche che in un altro form ci siano i FLAGS che mostrano lo stato del CTS, DTR ecc. del modem stesso. I dati ricevuti verranno inseriti nei campi di visualizzazione del form attivo. Se volessimo dare la possibilit di visualizzare gli stati del modem potremmo allatto della selezione della funzione, un pulsante premuto ad esempio, aggiornare il contenuto dei campi del form che andiamo visualizzare. Con C++Builder potremmo fare anche un'altra cosa. Dato che il FORM di fatto attivo ma non visualizzato mentre aggiorniamo i dati del nostro FORM attivo potremmo accedere ai dati del form nascosto e aggiornare anche questo facendo si che nellistante in cui lutente seleziona la funzione non dovremmo fare altro che visualizzare il form gi aggiornato. Come abbiamo detto prima C++Builder crea un riferimento usando il Name. __fastcall TCDialogDlg(TComponent* Owner); }; //--------------------------------------------------------------------------extern PACKAGE TCDialogDlg *CDialogDlg; Questo significa che abbiamo la variabile CDialogDlg. Se su questo abbiamo, come negli esempi di prima i campi dedit Edit1 possamo da un altr frm accedere direttamente ai valori contenuti in questi mediante : CDialogDlg->Edit1->Text = Valore da assegnare; Detto con parole sarebbe come dire : Il form rappresentato dalla variabile CdialogDlg che contiene il campo dedit Edit1. Il testo di questo campo viene assegnato al valore Valore da asegnare Questo possibile grazie al fatto ce i form sono attivati tutti allinizio del programma. Inoltre ogni oggetto posizionato nel programma viene assegnato ad una variabile. Grazie a questi riferimenti possibile accedere alle propriet e ai metodi di ciascuno di questi. Selezionando il tabulatore Events nellinspector delloggetto possibile creare le funzioni di gestione degli eventi. Come abbiamo detto prima Visual Studio necessita di tutte le definizioni fatte in modo esplicito per cui sicuramente pi complesso di C++Builder. Il metodo di gestione di questultimo chiamato VCL ovvero Visual Component Library dal cui nome si capisce che di fatto un metodo per il controllo visuale dei componenti. Noi abbiamo solo usato dei campi dedit ma queste regole legate alla creazione automatica di variabili rappresentanti i vari componenti vale anche per quanto riguarda gli oggetti indirizzati alla gestione di tabelle collegate a database. In pratica non sono le uniche differenze che ci sono tra i due ambienti di sviluppo. La pi sostanziosa sta di fatto nella filosofia legata al modello di gestione che usa Visual C++. Questo modello si chiama document/view. In pratica il sistema crea automaticamente due parti distinte di programma ciascuna delle quali dovrebbe interessarsi della gestione della parte documento e di quella della vista. Questo modello risulta essere abbastanza complesso da comprendere in particolar modo per chi inizia.

Quando si richiede a Visual Studio di creare un programma standard utilizzante le classi MFC questo crea di default 4 files .cpp tra cui due in particolare che si chiamano : NomeFileView.cpp NomeFileDoc.cpp Questi sono appunto i due files che gestiscono il meccanismo della vista/documento. Fortunatamente la teoria completa allinizio pu essere omessa se non per il fatto che solo alcuni concetti chiave dovrebbero essere visti. Come dicevamo prima C++Builder utilizza un metodo che semplifica la creazione di oggetti mediante il posizionamento diretto sul form e non solo per quanto riguarda componenti visibili ma anche per quello che concerne oggetti come connessioni TCP, seriali e cosi via. In altri linguaggi, come appunto il concorrente di C++Builder ovvero Visual Studio, quando si intende utilizzare un determinato oggetto e quindi tutte le sue funzioni, dobbiamo allinterno del programma dichiarare una variabile di una certa classe e poi accedere alle propriet di questa e utilizzare i metodi interni. Il posizionamento sul form di un componente visuale equivale a fare, con C++Builder, queste operazioni e quindi successivamente lutilizzo dei metodi sar possibile utilizzando come riferimento ilo nome attribuito al componente direttamente da video. Supponiamo di dover utilizzare nel nostro programma una delle COMMON DIALOG di Windows relativa alla selezione dei fonts. Windows dispone di oggetti standard che permettono appunto di visualizzare a video una dialog e da questa selezionare i fonts da utilizzare con relative dimensioni e colori. Come detto precedentemente Microsoft ha incapsulato allinterno delle classi MFC (Microsoft Foundation Class) tutti gli oggetti trattati nel SDK di Windows. Tra la varie classi esiste di fatto quella CFontDialog Se attiviamo lhelp ondine e andiamo a vedere le caratteristiche di questa classe ci accorgiamo che questa deriva da altre presenti allinterno di MFC ma quello che ci interessa maggiormente vedere che allinterno di questa classe esistono diversi membri relativi a parametri e alcuni metodi atti alla gestione delle funzionalit legate alla gestione a video dei fonts.

I dati e i metodi di questesempio sono :

CFontDialog Class Members


Data Members

m_cf
Construction

A structure used to customize a CFontDialog object.

CFontDialog Constructs a CFontDialog object.

Operations

DoModal GetCurrentFont GetFaceName GetStyleName GetSize GetColor GetWeight IsStrikeOut IsUnderline IsBold IsItalic

Displays the dialog and allows the user to make a selection. Retrieves the name of the currently selected font. Returns the face name of the selected font. Returns the style name of the selected font. Returns the point size of the selected font. Returns the color of the selected font. Returns the weight of the selected font. Determines whether the font is displayed with strikeout. Determines whether the font is underlined. Determines whether the font is bold. Determines whether the font is italic.

No ci interessa di fatto sapere praticamente a cosa servono questi metodi ma soltanto vedere che se allinterno del nostro programma ci trovassimo nella necessit di visualizzare una dialog di scelta fonts, dovremmo prima definire una variabile di questa classe, come ad esempio : CFontDialog dlgFont; e successivamente potremmo usare la variabile per accedere ai mebri e usare i suoi metodi con : dlgFont.GetSize(); ad esempio. La dichiarazione della variabile dovrebbe avenire dentro al programma e dovrebbe comqunue essere nostra cura consultare lhelp o un manuale per sapere quali sono i membri e i metodi interni. C++Builder semplifica la vita in quanto per poter utilizzare una variabile relativa ad una certa classe sarebbe sufficiente posizionarla a video sul form e quindi settare direttamente e membri selezionandoli a video. Allinterno del programma i nomi di questi sarebbero gli stessi e quindi il fatto di averli sottocchio sul foglio di lavoro ci evita di andare sempre sullhelp a vedere i contenuti di un certo oggetto.

Come potete vedere il nome assegnato nellObject Inspector di fatto il nome della variabile allocata automaticamente da C++Builder utilizzando la classe relativa aloggetto posizionato sul form, che in questo caso appunto di tipo FontDialog. Fate attenzione che questi oggetti posizionati sul form non sono visualizzati in fase di esecuzione.

In fase di progettazione potreste trovarvi davanti a dei forms anche molto affollati di oggetti ma ce poi in fase di esecuzione non sono visti. Ad esempio quello che vedete nellimmagine che segue fa parte di un progetto che gestisce il magazzino automatico di Montedison. Questo dialoga con dei sistemi PLC tramite canali UDP, gestisce database tramite Query ed esegue altre funzioni tramite questi oggetti posizionati a video che per al momento di runtime non vengono visualizzati.

Ricordatevi quindi che posizionare sul form equivale a dichiarare una variabile. Questa metodologia rende pi semplice lutilizzo di C++Builder. Vediamo ora la creazione di due programmi di gestione database simili utilizzando prima C++Builder e poi Visual Studio.

Un programma gestione database fatto con C++Builder


Per prima cosa dovremo richiedere a C++Builder di creare un nuovo progetto. Il database dovr gia essere creato. C++Builder chiaramente predilige i suoi formati o meglio quelli della Borland anche se di fatto nella toolbar esistono anche gli oggetti per accedere a questi tramite la metodologia ADO. Il form di gestione del database dovr avere in alto una lista di selezione dei records, sotto una toolbar di navigazione e sotto ancora i dati editati in forma estesa. Una volta creato il progetto C++Builder ci visualizzer a video il form di default su cui, selezionando da toolbar andremo a inserirci sopra una ADOConnection.

Selezionando loggetto a video e premendo F11 ci comparir l OBJECT INSPECTOR nel quale potremo specificare la stringa di connessione al database. Selezionando questa ci verranno mostrate le maschere in cui potremo scegliere i parametri relativi al tipo di collegamento con il database. Useremo lo stesso metodo che successivamente adotteremo con il progetto in Visual Studio. In pratica sceglieremo BUILD e il metodo Microsoft Jet 4.0 Ole DB Provide. Premendo NEXT potremo specificare il nome del database e nella finestra ancora dopo il metodo daccesso che deve essere READ/WRITE. Dopo avere posizionato la connessione al database ADO, alla quale C++Builder gli assegner automaticamente il nome di ADOConnection1, dovremo inserire il riferimento alla tabella. Posizioniamo un oggetto di tipo ADOTable e nel campo Connection selezioniamo il nome della connessione appena creata e nel campo TableName la tabella a cui vogliamo riferirci. Nel primo campo in alto presente il flag che specifica che quella tabella deve essere considerata attiva. Scegliamo true come valore.

Ora dovremo anche posizionare la sorgente dati chiamata DataSource la quale presente sotto il tab DataAccess. Inseriamo il primo oggetto a sinistra ovvero di tipo DataSource e nel campo dellinspector DataSet selezioniamo il nome della tabella e precisamente ADOTable1. A questo punto abbiamo sul form tutti gli oggetti necessari ai quali collegarci le liste, il navigatore e i campi dedit.

Iniziamo ora a posizionare gli oggetti necessari alla gestione del database partendo dalla lista di selezione e scorrimento. Nel TAB Data Controls selezioniamo licona relativa al DBGrid e espandiamola sul form.

Nel campo dellinspector DataSource selezioniamo la sorgente data che di fatto DataSource1. Lo stesso discorso legato al posizionamento lo facciamo per quanto riguarda il navigatore. Selezioniamo loggetto DBNavigator e mettiamolo nel form dove ci sembra meglio esteticamente. Sempre nel campo DataSource selezioniamo la sorgente dei dati DataSource1. Questa barra di navigazione quella che ci permette di scorrere i record, updatarli, cancellarli, inserirne di nuovi ecc.

Ora abbiamo la lista che ci permette di scorrere i record presenti nel database e la barra di navigazione. A questo punto dobbiamo inserire i singoli campi dedit che ci permetteranno di visualizzare in formato esteso le informazioni e di editarle. Per ogni campo dovremo inserire una stringa statica che specifichera d c quale campo si tratta e un campo dedit. Il campo di testo statico lo troviamo nel tabulatore sotto la voce Standard. Dovremo specificare la stringa da visualizzare. Il campo dedit invece si rova nello stesso TAB della lista e si chiama DBEdit.

Una volta inserito sul form dovremo anche in questo caso specificare la sorgente dati ovvero DataSource1 ma in piu, essendo ciascuno di questi relativi ad un campo del database, dovremo anche dire quale campo dee essere abbinato a quel campo dedit. Questo lo facciamo selezionando allinterno del data inspector il valore di DataField selezionandolo da quelli listati che chiaramente sono quelli presenti nella tabella scelta allatto della creazione delloggetto ADOTable.

A questo punto, dopo avere inserito ciascun campo che desideriamo editare, possiamo compilare il tutto ed eseguirlo. Avremo finito il nostro programma di gestione database. Visto che semplicit ci offre C++Builder ?

Un programma gestione database fatto con Visual C++


Visual Studio posside lo sterminato numero di metodi per il trattamento dei database a partire da quello ODBC per giungere ad ADO ed ADO+. Esistono sulla rete diversi libri che trattano solo questo grosso numero di metodi di gestione. Useremo tra questi il metodo che pi simile a quello utilizzato per C++Builder. Per fare questo dovremo utilizzare degli oggetti ADO che allinterno del sistema di sviluppo sono utilizzabili grazie alla possibilit di importare dentro ai programmi degli oggetti ActiveX. Il sistema degli ActiveX, ovvero i files .OCX, permettono di gestire in modo visuale determinati oggetti indirizzati a gestire certe funzionalit. Partiamo anche in questo caso partendo dalla creazione di un nuovo progetto di tipo MFC eseguibile di tipo DIALOG based. A questo punto dovremo richiedere a Visual Studio di inserire nella Toolbar dove sono presenti i componenti inseribili sulla dialog gli oggetti indirizzati alla gestione dei daabase mediante il metodo offerto da ADO. Selezioniamo da menu le voci : Project -> Add to project -> Components and Controls

Scegliamo Registered ActiveX Controls e scorriamo la lista fino a raggiungere :

Microsoft ADO Data Control 6.0 (SP4) (OLEDB).lnk

Microsoft DataGrid Control 6.0 (SP5) (OLEDB).lnk

Microsoft Masked Edit Control, version 6.0.lnk

Dovremo richiedere linserimento di tutti e tre I controlli. Per ciascuno di questi inseriti a video Visual Studio creer un certo numero di sorgenti atti alla loro gestione allinterno del programma. Questi componenti veranno aggiunti nella Toolbar sul foglio di lavoro.

Ora come primo oggetto da posizionare sulla dialog dovremo selezionare quello relativo alla connessione ADO. Questa dal punto di vista visivo si presenta come la navigation bar del C++Builder. Selezioniamo il componente posizionato e con il tasto destro del mosue scegliamo Properties. Ci comparir un finestra con diversi tabulatori in cui potremo selezionare il database a cui collegarci e tutte le sue propriet. La stringa creata per la connessione simile a quella creata con loggetto ADOConnection in C++Builder.

Qui i parametri da inserire sono di pi in quanto nel tabulatore RecordSource dovremo specificare anche la stringa relativa allo statement SQL che ci fornir la selezione dei records estratti dal database che verranno gestiti dalla barra di navigazione che di fatto rappresenta nel programma il punto di connessione al database.

Grazie questo meccanismo potremmo anche limitare i numero di records visualizzati nel programma. Ora inseriamo anche la DataGrid e dopo averlo fatto andiamo a selezionare nelle propriet, dove c il tabulatore All, la connessione al database che costituito dalla barra di navigazione appena creata.

Se non labbiamo cambiato noi il nome della connessione sr quella attribuita da Visual Studio ovvero IDC_ADODC1. Ora il terzo componente ActiveX inserito prima serve a gestire lediting dei dati. Anche in questo caso dovremo inserire un campo per ciascun campo che vorremo editare.

Sempre selezionando le propriet andiamo nel tabulatore All, quella relativa alla visualizzazione di TUTTE le propriet, e selezioniamo sia il DataSource che il DataFIeld relativo al campo che vogliamo associare a quel campo dedit. Anche in questo caso potremo salvare e compilare. In questo caso abbiamo utilizzato un metodo che non ci ha costretti ad utilizzare il ClassWizard, ma di fatto ho voluto tenere lesempio pi simile possibile a quello che abbiamo eseguito con C++Builder.

E meglio uno oppure laltro.


A questo punto viste le facilitazioni di C++Builder per quale motivo dovremmo utilizzare il sistema di sviluppo di Microsoft. Di fatto dobbiamo sempre pensare che Windows originario di Microsoft e questa per il suo sistema di sviluppo crea un numero di SDK notevoli. Chiaramente se non sar mai nostro interesse utilizzarli ma quello che ci prefiggiamo di fare e di fatto quello che ci offre C++Builder faremmo bene a usare questultimo. Rimane sempre il fatto che comunque usare uno non significa non poter usare laltro. Io personalmente uso per certi tipi di progetti il Microsoft mentre per altri il Borland. Se necessitiamo del programma di gestione veloce sicuramente il secondo pi idoneo.

Anche dal punto di vista didattico questo metodo di gestione visiva dei componenti semplifica lapprendimento delle filosofie object oriented. Sicuramente un ottimo strumento didattico. Per ora termino questo scritto promettendomi di farne uscire altri entro qualche tempo.

Copyright
Come riportato sugli altri volumi presenti su www.crackinguniversity2000.it sono accettate donazioni atte a coprire le spese di CU2000.

Potrebbero piacerti anche