Eccoci finalmente all'ultima parte della Guida all'Objective-C. L'argomento trattato oggi è l'uso di C++ e Objective-C.
Questo post è una traduzione in italiano della Guida all'Objective C, presente sul sito developer.apple.com a questo link. L'Objective C è il linguaggio di programmazione per creare applicazioni per iPhone. Questa guida potrebbe interessare a tutti gli sviluppatori che vogliono imparare le basi di questo linguaggio che è il fondamento per programmare nuove applicazioni per Mac Os X, iPhone ed iPad.
Questo post è una traduzione in italiano della Guida all'Objective C, presente sul sito developer.apple.com a questo link. L'Objective C è il linguaggio di programmazione per creare applicazioni per iPhone. Questa guida potrebbe interessare a tutti gli sviluppatori che vogliono imparare le basi di questo linguaggio che è il fondamento per programmare nuove applicazioni per Mac Os X, iPhone ed iPad.
Usare C++ Con Objective-C
Il compilatore Objective-C di Apple ti permette di mixare liberamente C++ e Objective-C nello stesso file sorgente. Questo linguaggio ibrido Objective-C/C++ è chiamato Objective-C++. Con esso puoi fare uso di librerie C++ esistenti dalle tue applicazioni Objective-C.
Mixare Caratteristiche di Linguaggio Objective-C e C++
In Objective-C++, puoi chiamare metodi da l'uno o l'altro linguaggio, nel codice C++ e nei metodi Objective-C. I puntatori ad oggetti in uno o l'altro linguaggio sono solo puntatori, e come tali possono essere usati ovunque. Ad esempio, puoi includere puntatori a oggetti Objective-C come membri dati di classi C++, e puoi includere puntatori ad oggetti C++ come variabili di istanza di classi Objective-C.
Il listato 14-1 illustra questo.
Nota: Xcode richiede che i nomi dei files abbiano un'estensione ".mm" per le estensioni Objective-C++ per poter essere abilitate dal compilatore.
Listato 14-1 Usare C++ ed istanze Objective-C come variabili di istanza
Il listato 14-1 illustra questo.
Nota: Xcode richiede che i nomi dei files abbiano un'estensione ".mm" per le estensioni Objective-C++ per poter essere abilitate dal compilatore.
Listato 14-1 Usare C++ ed istanze Objective-C come variabili di istanza
/* Hello.mm
* Compila con: g++ -x objective-c++ -framework Foundation Hello.mm -o hello
*/
#import
class Hello {
private:
id greeting_text; // Contiene una NSString
public:
Hello() {
greeting_text = @"Hello, world!";
}
Hello(const char* initial_greeting_text) {
greeting_text = [[NSString alloc] initWithUTF8String:initial_greeting_text];
}
void say_hello() {
printf("%s\n", [greeting_text UTF8String]);
}
};
@interface Greeting : NSObject {
@private
Hello *hello;
}
- (id)init;
- (void)dealloc;
- (void)sayGreeting;
- (void)sayGreeting:(Hello*)greeting;
@end
@implementation Greeting
- (id)init {
if (self = [super init]) {
hello = new Hello();
}
return self;
}
- (void)dealloc {
delete hello;
[super dealloc];
}
- (void)sayGreeting {
hello->say_hello();
}
- (void)sayGreeting:(Hello*)greeting {
greeting->say_hello();
}
@end
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Greeting *greeting = [[Greeting alloc] init];
[greeting sayGreeting]; // > Hello, world!
Hello *hello = new Hello("Bonjour, monde!");
[greeting sayGreeting:hello]; // > Bonjour, monde!
delete hello;
[greeting release];
[pool release];
return 0;
}
* Compila con: g++ -x objective-c++ -framework Foundation Hello.mm -o hello
*/
#import
class Hello {
private:
id greeting_text; // Contiene una NSString
public:
Hello() {
greeting_text = @"Hello, world!";
}
Hello(const char* initial_greeting_text) {
greeting_text = [[NSString alloc] initWithUTF8String:initial_greeting_text];
}
void say_hello() {
printf("%s\n", [greeting_text UTF8String]);
}
};
@interface Greeting : NSObject {
@private
Hello *hello;
}
- (id)init;
- (void)dealloc;
- (void)sayGreeting;
- (void)sayGreeting:(Hello*)greeting;
@end
@implementation Greeting
- (id)init {
if (self = [super init]) {
hello = new Hello();
}
return self;
}
- (void)dealloc {
delete hello;
[super dealloc];
}
- (void)sayGreeting {
hello->say_hello();
}
- (void)sayGreeting:(Hello*)greeting {
greeting->say_hello();
}
@end
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Greeting *greeting = [[Greeting alloc] init];
[greeting sayGreeting]; // > Hello, world!
Hello *hello = new Hello("Bonjour, monde!");
[greeting sayGreeting:hello]; // > Bonjour, monde!
delete hello;
[greeting release];
[pool release];
return 0;
}
Come puoi dichiarare strutture C in interfacce Objective-C, puoi anche dichiarare classi C++ in interfacce Objective-C. Come con le strutture C, le classi C++ definite dentro un'interfaccia Objective-C hanno uno scope globale, non annidato entro la classe Objective-C. (ciò è coerente con il modo in cui standard C (sebbene non C++) promuova le definizioni di strutture nidificate allo scope del file).
Per permettervi di condizionare il vostro codice basato su una variante del linguaggio, il compilatore Objective-C++ definisce entrambe le costanti di preprocessore __clusplus e __OBJC__, come specificato dagli standards dei linguaggi C++ e Objective-C rispettivamente.
Come detto precedentemente, Objective-C++ non permette di ereditare classi C++ dagli oggetti Objective-C, nè permette di ereditare classi Objective-C da oggetti C++.
Per permettervi di condizionare il vostro codice basato su una variante del linguaggio, il compilatore Objective-C++ definisce entrambe le costanti di preprocessore __clusplus e __OBJC__, come specificato dagli standards dei linguaggi C++ e Objective-C rispettivamente.
Come detto precedentemente, Objective-C++ non permette di ereditare classi C++ dagli oggetti Objective-C, nè permette di ereditare classi Objective-C da oggetti C++.
class Base { /* ... */ };
@interface ObjCClass: Base ... @end // ERROR!
class Derived: public ObjCClass ... // ERROR!
@interface ObjCClass: Base ... @end // ERROR!
class Derived: public ObjCClass ... // ERROR!
Diversamente dall'Objective-C, gli oggetti in C++ sono tipati staticamente, con polimorfismo a runtime disponibile come caso eccezionale. I modelli oggetto dei due linguaggi sono quindi non direttamente compatibili. Più fondamentalmente, il layout degli oggetti Obj-C e C++ in memoria è mutuamente incompatibile, ciò significa che generalmente è impossibile creare un'istanza di un oggetto che sarebbe valida dalla prospettiva di entrambi i linguaggi. Quindi, i due tipi di gerarchia non possono essere intercambiati.
Puoi dichiarare una classe C++ dentro una dichiarazione di calsse Objective-C. Il compilatore tratta queste classi come se fossero state dichiarate nel namespace globale, come segue:
Puoi dichiarare una classe C++ dentro una dichiarazione di calsse Objective-C. Il compilatore tratta queste classi come se fossero state dichiarate nel namespace globale, come segue:
@interface Foo {
class Bar { ... } // OK
}
@end
Bar *barPtr; // OK
class Bar { ... } // OK
}
@end
Bar *barPtr; // OK
Objective-C permette di usare strutture C (sia se dichiarate dentro una dichiarazione Objective-C sia se non dichiarate) come variabili di istanza.
@interface Foo {
struct CStruct { ... };
struct CStruct bigIvar; // OK
} ... @end
struct CStruct { ... };
struct CStruct bigIvar; // OK
} ... @end
Su Mac OS X 10.4 e successivi, se imposti il flag del compilatore fobjc-call-cxx-cdtors, puoi usare istanze di classi C++ che contengono funzioni virtuali e costruttori non banali e decostruttori come variabili di istanza.( il flag fobjc-call-cxx-cdtors è impostato di default in gcc-4.2.) I Costruttori sono invocati nel metodo alloc (specificamente, dentro class_createInstance), in ordine di dichiarazione immediatamente dopo che l'oggetto di cui sono membri è allocato. Il costruttore usato è il "costruttore pubblico senza argomenti". I distruttori sono invocati nl metodo dealloc (specificamente, dentro object_dispose), in ordine inverso della dichiarazione immediatamente prima che l'oggetto di cui sono membri è deallocato.
Mac OS X v10.3 e precedenti: Le seguenti precauzioni si applicano solo a Mac OS X v10.3 e precedenti.
Objective-C++ in modo simile si sforza di permettere a istanze di classi C++ di servire come variabili di istanza. Questo è possibile fintanto che la classe C+ in questione non ha funzioni membro virtuali definite. Se qualunque funzione membro virtuale fosse presente, la classe C++ potrebbe non servire come una variabile d'istanza Objective-C.
Mac OS X v10.3 e precedenti: Le seguenti precauzioni si applicano solo a Mac OS X v10.3 e precedenti.
Objective-C++ in modo simile si sforza di permettere a istanze di classi C++ di servire come variabili di istanza. Questo è possibile fintanto che la classe C+ in questione non ha funzioni membro virtuali definite. Se qualunque funzione membro virtuale fosse presente, la classe C++ potrebbe non servire come una variabile d'istanza Objective-C.
#import
struct Class0 { void foo(); };
struct Class1 { virtual void foo(); };
struct Class2 { Class2(int i, int j); };
@interface Foo : NSObject {
Class0 class0; // OK
Class1 class1; // ERROR!
Class1 *ptr; // OK—call 'ptr = new Class1()' from Foo's init,
// 'delete ptr' from Foo's dealloc
Class2 class2; // WARNING - constructor not called!
...
@end
struct Class0 { void foo(); };
struct Class1 { virtual void foo(); };
struct Class2 { Class2(int i, int j); };
@interface Foo : NSObject {
Class0 class0; // OK
Class1 class1; // ERROR!
Class1 *ptr; // OK—call 'ptr = new Class1()' from Foo's init,
// 'delete ptr' from Foo's dealloc
Class2 class2; // WARNING - constructor not called!
...
@end
C++ richiede che ogni istanza di una classe che contiene funzioni virtuali contenga un puntatore adatto nella tavola delle funzioni virtuali. Comunque, il runtime dell'Objective-C non può inizializzare il puntatore della tavola delle funzioni virtuali, perchè non è familiare con il modello degli oggetti C++. In modo analogo, il runtime di Objective-C non può spedire chiamate a costruttori C++ o decostruttori per quegli oggetti. Se una classe C++ ha qualsiasi costruttore definito da utente o distruttore, essi non sono chiamati. Il compilatore emette un warning in tali casi.
Objective-C non ha una nozione di nasmespaces annidati. Non puoi dichiarare classi Objective-C dentro namespaces C++, nè puoi dichiarare namespaces dentro classi Objective-C.
Classi Objective-C, protocolli, e categorie non possono essere dichiarati dentro un template C++, nè un template C++ può essere dichiarato nello scope di un'interfaccia, protocollo o categoria Objective-C.
Comunque, classi Objective-C potrebbero servire come parametri di template C++. Parametri dei template di C++ possono anche essere usati come riceventi o parametri (comunque non come selettori) in espressioni di messaggi Objective-C.
Objective-C non ha una nozione di nasmespaces annidati. Non puoi dichiarare classi Objective-C dentro namespaces C++, nè puoi dichiarare namespaces dentro classi Objective-C.
Classi Objective-C, protocolli, e categorie non possono essere dichiarati dentro un template C++, nè un template C++ può essere dichiarato nello scope di un'interfaccia, protocollo o categoria Objective-C.
Comunque, classi Objective-C potrebbero servire come parametri di template C++. Parametri dei template di C++ possono anche essere usati come riceventi o parametri (comunque non come selettori) in espressioni di messaggi Objective-C.
C++ Ambiguità Lessicali e Conflitti
Ci sono pochi identificatori che sono definiti nei files header Objective-C che ogni programma Objective-C deve includere. Questi identificatori sono id, Class, SEL, IMP, e BOOL.
In un metodo Objective-C, Il compilatore pre-dichiara gli identificatori self e super, in modo simile alla parola chiave this in C++. Comunque, diversamente dalla parola chiave this in C++, self e super sono context-sensitive (sensibili al contesto); potrebbero essere usati come identificatori ordinari fuori ai metodi Objective-C.
Nella lista dei parametri dei metodi dentro un protocollo, ci sono altre cinque parole chiave context-sensitive (oneway, in, out, inout, and bycopy). Queste non sono parole chiavi in altri contesti.
Dal punto di vista di un programmatore Objective-C, C++ aggiunge parecchie nuove parole chiavi. Puoi usare ancora le parole chiavi C++ come parte di un selettore Objective-C, così l'impatto non è troppo severo, ma non puoi usarle per nominare classi Objective-C o variabili di istanza. Ad esempio, anche se class è una parola chiave C++, puoi ancora usare il metodo class: di NSObject.
In un metodo Objective-C, Il compilatore pre-dichiara gli identificatori self e super, in modo simile alla parola chiave this in C++. Comunque, diversamente dalla parola chiave this in C++, self e super sono context-sensitive (sensibili al contesto); potrebbero essere usati come identificatori ordinari fuori ai metodi Objective-C.
Nella lista dei parametri dei metodi dentro un protocollo, ci sono altre cinque parole chiave context-sensitive (oneway, in, out, inout, and bycopy). Queste non sono parole chiavi in altri contesti.
Dal punto di vista di un programmatore Objective-C, C++ aggiunge parecchie nuove parole chiavi. Puoi usare ancora le parole chiavi C++ come parte di un selettore Objective-C, così l'impatto non è troppo severo, ma non puoi usarle per nominare classi Objective-C o variabili di istanza. Ad esempio, anche se class è una parola chiave C++, puoi ancora usare il metodo class: di NSObject.
[foo class]; // OK
Comunque, dato che è una parola chiave, non puoi usare class come il nome di una variabile:
NSObject *class; // Error
In Objective-C, i nomi per le classi e le categorie vivono in namespaces diversi. Che è, entrambi @interface foo e @interface(foo) possono esistere nello stesso codice sorgente. In Objective-C++, puoi anche avere una categoria i cui nomi combaciano con una classe o struttura C++.
Gli specificatori di protocollo e template usano la stessa sintassi per scopi diversi:
Gli specificatori di protocollo e template usano la stessa sintassi per scopi diversi:
id foo;
TemplateType bar;
TemplateType
Per evitare quest'ambiguità, il compilatore non permette che id venga usato come nome di template.
Infine, c'è un'ambiguità lessicale in C++ quando un'etichetta è seguita da un'espressione che menziona un nome globale, come in:
Infine, c'è un'ambiguità lessicale in C++ quando un'etichetta è seguita da un'espressione che menziona un nome globale, come in:
label: ::global_name = 3;
Lo spazio dopo i primi due punti è richiesto. Objective-C++ aggiunge un caso simile, il quale richiede anch'esso uno spazio:
receiver selector: ::global_c++_name;
Limitazioni
Objective-C++ non aggiunge caratteristiche di C++ alle classi Objective-C, né aggiunge caratteristiche Objective-C a classi C++. Ad esempio, non puoi usare la sintassi Objective-C per chiamare un oggetto C++, non puoi aggiungere costruttori o distruttori per un oggetto Objective-C, e non puoi usare le parole chiave this e self intercambiabilmente. Le gerarchie di classi sono separate; una classe C++ non può ereditare da una classe Objective-C, e una classe Objective-C non può ereditare da una classe C++. Inoltre la gestione delle eccezioni multi-language non è supportata. Cioè, un'eccezione lanciata in codice Objective-C non può essere catturata nel codice C++, e un'eccezione lanciata nel codice C++ non può essere catturata nel codice Objective-C. Per più informazioni sulle eccezioni in Objective-C, consultate "Gestione delle Eccezioni".
Continua...