Autore Topic: dead  (Letto 4506 volte)

Offline legacy

  • ASM Lover
  • *****
  • Post: 353
  • Karma: +14/-2
    • Mostra profilo
dead
« il: 08 Luglio 2013, 17:38:52 »
dead
« Ultima modifica: 16 Gennaio 2020, 22:02:59 da legacy »

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:come generare interfacce in C++ ???
« Risposta #1 il: 08 Luglio 2013, 23:33:55 »
Io ho sempre fatto a mano, mettendo i prototipi e le definizioni delle classi negli .h e l'implementazione nei .cpp (eccetto per i template dove per forza devi mettere definizione e implementazione nell'.h).

Questo è il modo tipico di programmare in C e C++ a quanto ne so. (che poi, la fatica di dover fare modifiche in 2 punti è limitata usando gli appositi IDE che te la fanno in automatico)

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:come generare interfacce in C++ ???
« Risposta #2 il: 09 Luglio 2013, 01:35:59 »
Eh, vuoi mettere la comodita' di farti generare moduli (vuoti, da riempire) ed interfacce ?
Boh. :D
Avere dei moduli all-in-one come in Java si, sarebbe la cosa migliore di tutte... peccato che han voluto tenere lo stile C di copiare bovinamente un file dentro l'altro. :-\

Citazione
anche quello Nokia, QT-coso che imputtana non poco le cose con i suoi "profili" e project templete
QtCreator secondo me è il miglior IDE sotto Linux, perchè non pesa due tonnellate e mezza (Eclipse), e perchè non ti obbliga a tenere i sorgenti disposti come vuole lui: tu crei un "progetto makefile" o "progetto makefile da sorgenti esistenti" (o qualcosa del genere), e lui ti lascia tutto come hai già disposto te, con il tuo Makefile scritto a mano; aggiunge solo un paio di file del suo progetto dove semplicemente ci sono le configurazioni di compilazione e avvio (tipo compilazione->make, avvio->nomefile parametro parametro).
Tutti gli altri IDE che ho provato ti obbligano a organizzare il progetto come vogliono loro e ciò da molto fastidio anche a me.

Si potrebbe dire che il tool che usi ti obbliga a fare i sorgenti organizzati come vuole lui, quasi come un IDE. :P

Citazione
Quindi va bene cosi', e per il C++, boh, si presta a questo schema, manca solo la generazione delle interfacce (hai detto niente).
Eh però il C++ è ben più complesso del C, non ci sono solo prototipi e variabili extern: c'hai i template che li devi per forza tenere tutti in header, poi le classi le cui funzioni membro puoi decidere se mettere nel file separato oppure direttamente nell'header (la seconda possibilità in teoria permette al compilatore di fare l'inline durante la compilazione, ma io le metto sempre in un file separato anche se sono 2 righe).

Vedi lì se il tuo programmino tratta bene anche col C++, altrimenti boh, se proprio lo vuoi si può cercarne di tirarne fuori uno simile...
Ad esempio, per evitare di fare un'intero parser C++, si potrebbe dire: ogni file .c++ è diviso in 2 sezioni: quella delle intestazioni e quella di implementazione. Il programmino-parser-generatore non farebbe altro che estrarre le informazioni di intestazione e metterle nel loro file per accederci da altre parti; in questo modo hai tutto nello stesso file.

Esempio:
Codice: [Seleziona]
/**** miaclasse.cpp ****/

//*[BEGIN HEADER]
class MiaClasse
{
    public:
        MiaClasse();
        ~MiaClasse();
        int getStuff();
        void setStuff(int stuff);
    private:
        int stuff;
};
//*[END HEADER]

MiaClasse::MiaClasse() { stuff = 0; }
MiaClasse::~MiaClasse() {}

int MiaClasse::getStuff() { return stuff; }
void MiaClasse::setStuff(int a) { stuff = a; }

Questo è un file .cpp valido. Ora il tuo pre-pre-processore genera:

Codice: [Seleziona]
/* miaclasse.h */
/* Extract from miaclasse.cpp */
/* DO NOT EDIT */

class MiaClasse
{
    public:
        MiaClasse();
        ~MiaClasse();
        int getStuff();
        void setStuff(int stuff);
    private:
        int stuff;
};

Semplice ma efficace. :D

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re:come generare interfacce in C++ ???
« Risposta #3 il: 09 Luglio 2013, 11:08:39 »
Citazione da: Z80Fan
Tutti gli altri IDE che ho provato ti obbligano a organizzare il progetto come vogliono loro e ciò da molto fastidio anche a me.

Visual C++ ti consente di avere il progetto separato dai sorgenti, con o senza makefile esterno. Volendo puoi usare Visual C++ come editor e poi compilare via makefile.

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:come generare interfacce in C++ ???
« Risposta #4 il: 09 Luglio 2013, 17:17:31 »
Visual C++ ti consente di avere il progetto separato dai sorgenti, con o senza makefile esterno. Volendo puoi usare Visual C++ come editor e poi compilare via makefile.

Si, intendevo dire IDE per Linux. :D
Visual C++ non sapevo, ma ero certo che ti permettesse di gestirti come vuoi, date la quantità di impostazioni che ha.

I vantaggi di avere tutto in un unico modulo sono pochi rispetto a questi

Secondo me un approccio tipo Java sarebbe ottimo anche per il C++: un singolo file cpp indica quali "oggetti" vuole rendere visibili all'esterno, e gli altri moduli si riferiscono al nome del file (senza estensione).

Per i file che non esportano template, il compilatore può generarli singolarmente e metterli in un apposito file oggetto da linkare (simile ai .class ma che è usato solo a tempo di compilazione per generare l'eseguibile finale), che contiene tutte le informazioni per poter compilare i sorgenti che lo includono (quindi non solo il codice binario ma anche i prototipi delle funzioni e la definizione di classi/strutture).
Se il sorgente del modulo contiene tempate, il compilatore può andare a cercarsi la definizione all'interno del sorgente e compilarla per il tipo di dato richiesto; oppure nel file oggetto del modulo si può inserire il codice del template pulito e semplificato solo per poter essere poi usato per creare la versione specifica.

Si ha il vantaggio che il template compilato specifico per un tipo di dato può essere cache-ato in un suo file binari opposito, così non deve essere ricompilato ogni volta che un modulo lo include.
Pensiamo ad esempio un videogioco, può avere una classe Vector3D che viene specializzata in int e float ma nient'altro; il compilatore quando incontra il primo file che usa la versione int, la compila e la mette in un suo file, così che tutti i successivi moduli possono usare direttamente la versione binaria invece di perdere tempo nel parsing, compilazione, ottimizzazione.

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re:come generare interfacce in C++ ???
« Risposta #5 il: 09 Luglio 2013, 17:28:53 »
L'unica rottura di palle dei compilatori C++ è che nessuno supporta la compilazione separata dei template. Lo standard C++ la prevede, ma nella pratica non esiste e quindi devi portartela dietro nei file .h

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re:come generare interfacce in C++ ???
« Risposta #6 il: 09 Luglio 2013, 18:33:01 »
il fatto è che viene molto più semplice implementare i template a botte di copia-incolla, come se fossero dei #define particolarmente sofisticati. Per fare la compilazione separata di un template bisognerebbe avere un sistema dei tipi supportato dal runtime, con una specie di "tipo generico" stile "id" dell'Objective-C oppure l'Object del Java o robe simili. Al momento non mi vengono altri modi per farlo in C++, anche perchè la compilazione di una class in C++ richiede la conoscenza del size della classe stessa, ed essendo templata il size smette di essere una costante (sizeof infatti non è una vera funzione ma un "operator" costante che viene valutato a compile time).

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:come generare interfacce in C++ ???
« Risposta #7 il: 10 Luglio 2013, 02:53:56 »
Questo "Explicit Instantiation" trick sembra essere un workaround

Certo, "ovviamente" funziona, perchè il compilatore, in foo.cpp genera il codice necessario per fornire la specializzazione sui tipi che gli hai passato, e quindi il linker riesce a trovare da qualche parte i simboli per linkare tutto alla fine.

Questo metodo però funziona solo se sai che specializzazioni ti servono, ad esempio come il Vector3D di cui parlavo prima, dove sai che avrai solo int e float e mai tipo string.
In casi più generici (es. i contenitori della STL) è impossibile farlo con questo trucco.

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re:come generare interfacce in C++ ???
« Risposta #8 il: 10 Luglio 2013, 19:20:19 »
certo che si può fare, però nel primo caso gli operatori sono automaticamente inlined e guadagni in performance, mentre nel secondo caso potrebbe riuscire a fare l'inline oppure no, dipende da come gli gira il testicolo sinistro.

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re:come generare interfacce in C++ ???
« Risposta #9 il: 10 Luglio 2013, 19:39:28 »
Ma no, che friend :P

semplicemente nel .h ci metti

Codice: [Seleziona]
#pragma once
class Suca {
public:
   int prototipo(int c, int d);
};

e nel .Cpp ci metti:
Codice: [Seleziona]
#include "suca.h"

int Suca::prototipo(int c, int d)
{
    return c + d;
}
« Ultima modifica: 10 Luglio 2013, 19:46:08 da TheKaneB »

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re:come generare interfacce in C++ ???
« Risposta #10 il: 10 Luglio 2013, 19:48:08 »
per protopipi più complessi, tipo gli operator fai così:

Codice: [Seleziona]
class Complex
{
public:
    Complex& operator - (const Complex &rhs);
};

e nel cpp

Codice: [Seleziona]
Complex& Complex::operator - (const Complex &rhs)
    {
        re = Re() + rhs.Re();
        im = Im() + rhs.Im();
        return *this;
    }

tutto il segreto sta nel mettere NomeClass:: davanti al nome del metodo che stai definendo.

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:come generare interfacce in C++ ???
« Risposta #11 il: 10 Luglio 2013, 20:09:03 »
Esatto, metti solo i prototipi nel .h, e poi le implementazioni nel .cpp, come l'esempio di MiaClasse. :D

Ovviamente per le cose tipo "ostream& operator << (ostream & t, const Complex &c)", le lasci così perchè non appartengono alla classe.

Una cosa un po' meh da stare attento è se metti parametri con valori di default; la specifica del default la devi mettere solo nei prototipi dell'.h, ma non nel .cpp, altrimenti il compilatore te lo fa notare ma spesso con un messaggio che non è proprio chiaro chiaro...
Se non hai capito cosa voglio dire, ignora che tanto non incorrerai mai in questo problema. :P

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:come generare interfacce in C++ ???
« Risposta #12 il: 10 Luglio 2013, 20:36:54 »
ho avuto qualche problema con i const, tolti di mezzo

Cosa diceva? Sarebbe meglio tenerli i const a meno di cose strambe del compilatore.

Offline Z80Fan

  • Administrator
  • Guru
  • *****
  • Post: 1671
  • Karma: +13/-2
    • Mostra profilo
    • http://z80fan.altervista.org
Re:come generare interfacce in C++ ???
« Risposta #13 il: 10 Luglio 2013, 22:36:14 »
mah,farfugliava cose a me ancora incomprensibili, domani lo riguardo un attimo,
Postaci gli errori interi che te li interpretiamo noi; GCC specialmente non è rinomato per la qualità dei suoi messaggi... :-\

Citazione
c'e' un casino bestia anche per capire come accidenti si implementa ++ e --, e tanta altra roba, tra cui "[]".
Ma no, sono facili lo stesso... se sai il trucco. :P

Il operator[] lo metti come membro della classe, dandogli come parametro il tipo di dato che vuoi usare come indice; un array di interi sarà:
int operator[](int indice);   // oppure unsigned int indice

Oppure magari vuoi una mappa:
Valore operator[](string chiave);

Per i ++ e -- c'è un piccolo dettaglio: per differenziare tra preincremento (++a) e postincremento (a++), devi passargli un parametro fittizio:
R operator++();      // PREincremento ++a
R operator++(int);   // POSTincremento a++

Con R il tipo di ritorno.

Il parametro puoi anche metterlo senza nome, perchè non ha nessun valore, anzi non devi neanche proprio usarlo; serve solo al compilatore per differenziare i due casi. Lo stesso vale per --.
Anche questi li metti come membro dentro la classe.

Qua hai tutta la lista degli operatori e i loro prototipi:
http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B

Tags: