Use C ++ com cacau em vez de Objective-C?

122

Eu gostaria de escrever aplicativos que usem C ++ e as estruturas Cocoa porque a Apple não está tornando o Carbon 64 bits capaz. O C ++ parece bastante simples em sua implementação no Linux e Windows, mas no Mac OS X parece que são necessários trechos de código específicos adicionais da Apple (como um wrapper Obj-C). Parece também que a Apple está forçando os desenvolvedores a escrever em Objective-C, em vez de C ++, embora eu possa estar errado.

Estou tentando encontrar um caminho para escrever código no Mac que seria fácil de manter entre plataformas. Ter que escrever código em C ++ para Linux / Windows e depois reescrever grandes partes no Objective-C seria muito ineficiente.

Existe uma maneira de escrever código em C ++ que será suportado para o futuro e suportado no Xcode? Além disso, se isso for possível, como eu misturaria C ++ e Objective-C no Xcode? Obrigado.

Brock Woolf
fonte

Respostas:

110

Você não pode escrever um aplicativo Cocoa inteiramente em C ++. O cacau depende muito dos recursos de vinculação tardia do Objective-C para muitas de suas principais tecnologias, como vinculações de valor-chave, delegados (estilo cacau) e o padrão de ação-alvo. Os requisitos de ligação tardia tornam muito difícil implementar a API do Cocoa em uma linguagem digitada vinculada ao tempo de compilação, como o C ++ ⁱ. Obviamente, você pode escrever um aplicativo C ++ puro que seja executado no OS X. Ele simplesmente não pode usar as APIs do Cocoa.

Portanto, você tem duas opções se desejar compartilhar código entre aplicativos C ++ em outras plataformas e seu aplicativo baseado em Cocoa. O primeiro é escrever a camada do modelo em C ++ e a GUI no cacau. Essa é uma abordagem comum usada por aplicativos muito grandes, incluindo o Mathematica . Seu código C ++ pode permanecer inalterado (você não precisa de extensões "funky" da apple para escrever ou compilar C ++ no OS X). Sua camada do controlador provavelmente fará uso do Objective-C ++ (talvez a extensão "descolada" da Apple a que você se refere). Objective-C ++ é um superconjunto de C ++, assim como Objective-C é um superconjunto de C. No Objective-C ++, você pode fazer chamadas no estilo objc passando mensagens (como [some-objc-object callMethod];) de dentro de uma função C ++. Por outro lado, você pode chamar funções C ++ de dentro do código ObjC, como:

@interface MyClass {
    MyCPPClass *cppInstance;
}
@end

@implementation MyClass
- (id)init {
    if(self = [super init]) {
        cppInstance = new MyCPPClass();
    }
    return self;
}
- (void) dealloc {
    if(cppInstance != NULL) delete cppInstance;
    [super dealloc];
}
- (void)callCpp {
    cppInstance->SomeMethod();
}
@end

Você pode descobrir mais sobre o Objective-C ++ no guia de idiomas da Objective-C . A camada de visualização pode então ser pura Objective-C.

A segunda opção é usar um kit de ferramentas C ++ entre plataformas. The Qtkit de ferramentas pode ser adequado. Os kits de ferramentas de plataforma cruzada geralmente são desprezados pelos usuários de Mac, porque não obtêm todos os detalhes de aparência e aparência exatamente corretos e os usuários de Mac esperam polimento na interface do usuário dos aplicativos Mac. No entanto, o Qt faz um trabalho surpreendentemente bom e, dependendo do público e do uso do seu aplicativo, pode ser bom o suficiente. Além disso, você perderá algumas das tecnologias específicas do OS X, como Core Animation e algumas funcionalidades do QuickTime, embora haja substituições aproximadas na API Qt. Como você aponta, o Carbon não será portado para 64 bits. Desde que o Qt é implementado nas APIs do Carbon, a Trolltech / Nokia precisou portar o Qt para a API do cacau para torná-lo compatível com 64 bits. Meu entendimento é que a próxima versão do Qt (atualmente em versão candiate) conclui essa transição e é compatível com 64 bits no OS X. Você pode dar uma olhada na fonte do Qt 4.5 se estiver interessado em integrar o C ++ e as APIs do Cocoa.


Por um tempo, a Apple disponibilizou a API Cocoa para Java, mas a ponte exigiu um amplo ajuste manual e não foi capaz de lidar com as tecnologias mais avançadas, como as Vinculações de valor-chave descritas acima. Atualmente, linguagens dinamicamente tipadas e vinculadas ao tempo de execução, como Python, Ruby etc., são a única opção real para escrever um aplicativo Cocoa sem o Objective-C (embora, obviamente, essas pontes usem o Objective-C sob o capô).

Barry Wark
fonte
Atualmente, estou tentando portar meu pequeno aplicativo Ogre3D, parece MUITO doloroso. A apple está tentando converter todos para Objc ou isso é realmente um recurso?
jokoon
68

Bem, pode parecer bobagem, mas, na verdade, podemos escrever código C ++ puro para criar GUI para Mac OS X, mas precisamos vincular o framework Cocoa.

/*
 * test1.cpp
 * This program shows how to access Cocoa GUI from pure C/C++
 * and build a truly functional GUI application (although very simple).
 * 
 * Compile using:
 *   g++ -framework Cocoa -o test1 test1.cpp
 *
 * that will output 'test1' binary.
 */


#include <CoreFoundation/CoreFoundation.h>
#include <objc/objc.h>
#include <objc/objc-runtime.h>
#include <iostream>

extern "C" int NSRunAlertPanel(CFStringRef strTitle, CFStringRef strMsg,
                               CFStringRef strButton1, CFStringRef strButton2, 
                               CFStringRef strButton3, ...);


int main(int argc, char** argv)
{
    id app = NULL;
    id pool = (id)objc_getClass("NSAutoreleasePool");
    if (!pool)
    {
        std::cerr << "Unable to get NSAutoreleasePool!\nAborting\n";
        return -1;
    }
    pool = objc_msgSend(pool, sel_registerName("alloc"));
    if (!pool)
    {
        std::cerr << "Unable to create NSAutoreleasePool...\nAborting...\n";
        return -1;
    }
    pool = objc_msgSend(pool, sel_registerName("init"));

    app = objc_msgSend((id)objc_getClass("NSApplication"),
                       sel_registerName("sharedApplication"));

    NSRunAlertPanel(CFSTR("Testing"),
                    CFSTR("This is a simple test to display NSAlertPanel."),
                    CFSTR("OK"), NULL, NULL);

    objc_msgSend(pool, sel_registerName("release"));
    return 0;
}
FX. J. Adi Lima
fonte
16
Isso é maravilhoso. Existem exemplos mais complicados disponíveis? Por exemplo, abrindo um NSWindow?
I283
test1.cpp: Na função 'int main (int, char **)': test1.cpp: 26: 48: erro: não é possível converter 'Class {aka objc_class *}' para 'id {aka objc_object *}' no ID de inicialização pool = objc_getClass ("NSAutoreleasePool"); ^ test1.cpp: 41: 61: erro: não é possível converter 'Classe {aka objc_class *}' em 'id {aka objc_object *}' para o argumento '1' em 'objc_object * objc_msgSend (id, SEL, ...)' sel_registerName ("sharedApplication")); ^
Jichao
6
@Jichao ver compatibilidade Clang com tipos Objective-C internos - a correção é simples: substituir objc_getClasscom(id)objc_getClass
Dmitry Isaev
Como posso usar um std :: string para definir, por exemplo. o título do painel de alerta? Eu tentei usar c_str () e iguais, mas nada funcionou ...
mdre
1
Isso não é mais compilado no macOS Catalina
JC Rocamonde
18

Sim, você pode apenas usar C ++ (ou seja, gravá-lo em arquivos * .cpp) e até misturar C ++ e Objective-C em arquivos * .mm (o código Objective-C padrão é armazenado em arquivos * .m).

Obviamente, você ainda precisará usar o Objective-C para sua interface com o usuário e criar wrappers Objective-C para seus objetos C ++. Outra opção é mudar para o Qt, que é uma estrutura C ++ que suporta Windows, Mac OS X e Linux - e será lançada sob a LGPL na próxima versão 4.5.

fhe
fonte
22
Observe que se você usar o Qt, seu aplicativo será péssimo. Os aplicativos baseados em Qt não parecem com aplicativos Mac nativos. (Para um exemplo, consulte Google Earth.)
Peter Hosey
15
Peter: Isso não é verdade. Os aplicativos baseados em Qt podem parecer idênticos aos aplicativos nativos do Mac; você só precisa fazer ajustes por plataforma, algo que é muito mais fácil do que escrever uma GUI nativa em cada plataforma.
Mike McQuaid
11
Mike, você está mal informado. Entre suas outras deficiências, os aplicativos baseados em Qt no mac não usam os controles nativos, e a biblioteca Qt faz todo o desenho em si. Isso significa que os aplicativos Qt não recebem nenhuma aceleração de hardware para renderização em 2D, eles não ficam sincronizados com as alterações na interface do usuário que a Apple faz nos controles padrão, e um aplicativo Qt não pode oferecer conformidade ou capacidade de script ADA, a menos que você os reinvente. rodas você mesmo. Em outras palavras, NÃO TENTE enviar um aplicativo Qt no Mac. O Google pode se safar: você não pode.
NSResponder
13
Eles usam os controles nativos, é por isso que o Qt tem uma versão de cacau e carbono. Ele tem outros problemas, mas muitas pessoas enviam aplicativos Qt para Mac e funcionam bem (e perfeitamente com alguns ajustes).
Mike McQuaid
2
Basta usar de controle nativo não significa que ele vai olhar e sentir como aplicativos nativos. O que faz um sentimento nativo é a diferença de cada sistema operacional. Se você ajustar seu aplicativo para ser sentido em uma plataforma específica, ele não será nativo em outra plataforma. E o ajuste fino de pequenos comportamentos em uma camada abstraída é sempre mais difícil do que na camada nativa.
eonil
9

Sim, você pode misturá-los.

Você precisa usar o Objective-C para operar diretamente em seus objetos da GUI e receber notificações deles.

Esses objetos Objective-C podem chamar diretamente a lógica C ++ se você os colocar em arquivos .mm, em vez dos arquivos puros de Objective-C .m. Observe que você pode ver conselhos (muito) mais antigos sugerindo o uso de um .M maiúsculo para indicar Objective-C ++, mas isso é muito esquisito e provavelmente confunde você e o compilador.

Você não precisa agrupar todos os objetos C ++, mas seu código Objective-C precisará conter ponteiros para eles.

A Apple não publica mais nenhuma amostra mostrando como fazer isso.

Há um ótimo vídeo de Peter Steinberger hospedado no Realm [Objective] C ++: O que poderia dar errado? Eu recomendo para qualquer pessoa que ainda esteja usando o Objective-C ++ e você pode examinar rapidamente a transcrição.

Andy Dent
fonte
@SteveS seu link está quebrado também
fferri
@fferi - O link do Steinberger acima foi corrigido. Carbon Cocoa Integration foi de 2007 em developer.apple.com, a Apple o removeu. Isso indica que você REALMENTE não deve escrever um novo código usando as APIs do Carbon. Nesse ponto, mesmo manter o código existente usando Carbon é arriscado. Consulte a resposta aceita para esta pergunta, ou esta, se você precisar misturar C ++ / Objective C, mas não usar Carbon. Dito isto, aqui: Integração carbono-cacau
SteveS
4

Se você deseja usar o C ++ vanilla comum, isso é absolutamente suportado e realmente não é diferente de qualquer outra plataforma. O Xcode ainda possui um modelo em Arquivo> Novo projeto> Utilitário de linha de comando> Ferramenta C ++. Além disso, várias bibliotecas populares de código aberto (libcurl, libxml2, sqlite, etc) vêm com o OS X e estão disponíveis para vinculação dinâmica. Você não precisa usar cacau ou algo específico da Apple, se não quiser.

Se você deseja usar o cacau em certas partes do seu aplicativo, consulte Objective-C ++ . Você pode misturar C ++ e Objective-C no mesmo arquivo, fornecendo uma extensão de .mm ou clicando com o botão direito do mouse no arquivo no Xcode e selecionando Obter informações> Geral e alterando o Tipo de arquivo para sourcecode.cpp.objcpp. A segunda opção é útil se você tiver um arquivo .cpp no ​​qual deseja usar o Objective-C em um #ifdef específico do Mac.

Matt Stevens
fonte
1
BTW, modelo da (muito útil) C ++ é ido com versões recentes do Xcode (4.xe 5.x)
Jay
1

Embora esta seja uma pergunta de anos ...

Eu tentei fazer wrapper C ++ de algumas classes de cacau .

Foi uma experiência bastante agradável. O C ++ forneceu uma segurança de tipo melhor que o Objective-C e me fez escrever menos código. Mas o tempo de compilação e a segurança da memória são piores. É possível, mas alguns recursos dinâmicos não foram fáceis de manusear. Eu acho que não faz sentido lidar com isso em C ++.

Enfim, meu projeto foi finalmente abandonado devido ao anúncio de Swift. Ele limpou todos os motivos pelos quais eu queria usar C ++ no início e fornece ainda mais e melhor.

eonil
fonte
0

Se você está escrevendo um aplicativo puramente gráfico, ou seja, está desenhando tudo usando o código, considere openFrameworks . É uma linguagem de programação gráfica de código aberto criada sobre C / C ++. Possui complementos que permitem que as pessoas estendam o idioma. Eles têm um addon para o iphone . Acredito que ele vem com a biblioteca e os projetos XCode que ajudarão você a compilar aplicativos para o iPhone e iPod touch.

milesmeow
fonte