Você pode misturar C ++ com Objective-C se fizer isso com cuidado. Existem algumas ressalvas, mas, de modo geral, elas podem ser misturadas. Se você quiser mantê-los separados, você pode configurar uma função de wrapper C padrão que dá ao objeto Objective-C uma interface de estilo C utilizável de código não Objective-C (escolha nomes melhores para seus arquivos, eu escolhi esses nomes para verbosidade):
MyObject-C-Interface.h
#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__
// This is the C "trampoline" function that will be used
// to invoke a specific Objective-C method FROM C++
int MyObjectDoSomethingWith (void *myObjectInstance, void *parameter);
#endif
MyObject.h
#import "MyObject-C-Interface.h"
// An Objective-C class that needs to be accessed from C++
@interface MyObject : NSObject
{
int someVar;
}
// The Objective-C member function you want to call from C++
- (int) doSomethingWith:(void *) aParameter;
@end
MyObject.mm
#import "MyObject.h"
@implementation MyObject
// C "trampoline" function to invoke Objective-C method
int MyObjectDoSomethingWith (void *self, void *aParameter)
{
// Call the Objective-C method using Objective-C syntax
return [(id) self doSomethingWith:aParameter];
}
- (int) doSomethingWith:(void *) aParameter
{
// The Objective-C function you wanted to call from C++.
// do work here..
return 21 ; // half of 42
}
@end
MyCPPClass.cpp
#include "MyCPPClass.h"
#include "MyObject-C-Interface.h"
int MyCPPClass::someMethod (void *objectiveCObject, void *aParameter)
{
// To invoke an Objective-C method from C++, use
// the C trampoline function
return MyObjectDoSomethingWith (objectiveCObject, aParameter);
}
A função wrapper não precisa estar no mesmo .m
arquivo que a classe Objective-C, mas o arquivo em que ela existe precisa ser compilado como código Objective-C . O cabeçalho que declara a função wrapper precisa ser incluído no código CPP e Objective-C.
(NOTA: se o arquivo de implementação Objective-C receber a extensão ".m", ele não será vinculado ao Xcode. A extensão ".mm" diz ao Xcode para esperar uma combinação de Objective-C e C ++, ou seja, Objective-C ++. )
Você pode implementar o acima de uma maneira orientada a objetos usando o idioma PIMPL . A implementação é apenas ligeiramente diferente. Resumindo, você coloca as funções de wrapper (declaradas em "MyObject-C-Interface.h") dentro de uma classe com um ponteiro void (privado) para uma instância de MyClass.
MyObject-C-Interface.h (PIMPL)
#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__
class MyClassImpl
{
public:
MyClassImpl ( void );
~MyClassImpl( void );
void init( void );
int doSomethingWith( void * aParameter );
void logMyMessage( char * aCStr );
private:
void * self;
};
#endif
Observe que os métodos de wrapper não requerem mais o ponteiro void para uma instância de MyClass; agora é um membro privado de MyClassImpl. O método init é usado para instanciar uma instância MyClass;
MyObject.h (PIMPL)
#import "MyObject-C-Interface.h"
@interface MyObject : NSObject
{
int someVar;
}
- (int) doSomethingWith:(void *) aParameter;
- (void) logMyMessage:(char *) aCStr;
@end
MyObject.mm (PIMPL)
#import "MyObject.h"
@implementation MyObject
MyClassImpl::MyClassImpl( void )
: self( NULL )
{ }
MyClassImpl::~MyClassImpl( void )
{
[(id)self dealloc];
}
void MyClassImpl::init( void )
{
self = [[MyObject alloc] init];
}
int MyClassImpl::doSomethingWith( void *aParameter )
{
return [(id)self doSomethingWith:aParameter];
}
void MyClassImpl::logMyMessage( char *aCStr )
{
[(id)self doLogMessage:aCStr];
}
- (int) doSomethingWith:(void *) aParameter
{
int result;
// ... some code to calculate the result
return result;
}
- (void) logMyMessage:(char *) aCStr
{
NSLog( aCStr );
}
@end
Observe que MyClass é instanciado com uma chamada para MyClassImpl :: init. Você poderia instanciar MyClass no construtor de MyClassImpl, mas isso geralmente não é uma boa ideia. A instância MyClass é destruída do destruidor de MyClassImpl. Tal como acontece com a implementação do estilo C, os métodos de wrapper simplesmente se referem aos respectivos métodos de MyClass.
MyCPPClass.h (PIMPL)
#ifndef __MYCPP_CLASS_H__
#define __MYCPP_CLASS_H__
class MyClassImpl;
class MyCPPClass
{
enum { cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42 };
public:
MyCPPClass ( void );
~MyCPPClass( void );
void init( void );
void doSomethingWithMyClass( void );
private:
MyClassImpl * _impl;
int _myValue;
};
#endif
MyCPPClass.cpp (PIMPL)
#include "MyCPPClass.h"
#include "MyObject-C-Interface.h"
MyCPPClass::MyCPPClass( void )
: _impl ( NULL )
{ }
void MyCPPClass::init( void )
{
_impl = new MyClassImpl();
}
MyCPPClass::~MyCPPClass( void )
{
if ( _impl ) { delete _impl; _impl = NULL; }
}
void MyCPPClass::doSomethingWithMyClass( void )
{
int result = _impl->doSomethingWith( _myValue );
if ( result == cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING )
{
_impl->logMyMessage( "Hello, Arthur!" );
}
else
{
_impl->logMyMessage( "Don't worry." );
}
}
Agora você acessa chamadas para MyClass por meio de uma implementação privada de MyClassImpl. Essa abordagem pode ser vantajosa se você estiver desenvolvendo um aplicativo portátil; você poderia simplesmente trocar a implementação de MyClass por uma específica para a outra plataforma ... mas, honestamente, se esta é uma implementação melhor é mais uma questão de gosto e necessidades.
extern "C"
antes deint MyObjectDoSomethingWith
Você pode compilar seu código como Objective-C ++ - a maneira mais simples é renomear seu .cpp como .mm. Ele irá então compilar corretamente se você incluir
EAGLView.h
(você estava recebendo tantos erros porque o compilador C ++ não entendia nenhuma das palavras-chave específicas do Objective-C), e você pode (na maior parte) misturar Objective-C e C ++ como quiser gostar.fonte
A solução mais fácil é simplesmente dizer ao Xcode para compilar tudo como Objective C ++.
Defina suas configurações de projeto ou destino para Compile Sources As to Objective C ++ e recompile.
Então você pode usar C ++ ou Objective C em qualquer lugar, por exemplo:
Isso tem o mesmo efeito que renomear todos os seus arquivos de origem de .cpp ou .m para .mm.
Existem duas pequenas desvantagens nisso: o clang não pode analisar o código-fonte C ++; alguns códigos C relativamente estranhos não compilam em C ++.
fonte
Passo 1
Crie um arquivo c objetivo (arquivo .m) e seu arquivo de cabeçalho correspondente.
// Arquivo de cabeçalho (chamamos de "ObjCFunc.h")
// Arquivo Objective C correspondente (nós o chamamos de "ObjCFunc.m")
Passo 2
Agora vamos implementar uma função c ++ para chamar a função c objetiva que acabamos de criar! Portanto, para isso definiremos um arquivo .mm e seu arquivo de cabeçalho correspondente (o arquivo ". Mm" deve ser usado aqui porque poderemos usar codificação Objective C e C ++ no arquivo)
// Arquivo de cabeçalho (chamamos de "ObjCCall.h")
// Arquivo Objective C ++ correspondente (nós o chamamos de "ObjCCall.mm")
etapa 3
Chamar a função c ++ (que realmente chama o método c objetivo)
//Última chamada
Espero que funcione!
fonte
Você precisa fazer com que seu arquivo C ++ seja tratado como Objective-C ++. Você pode fazer isso no xcode renomeando foo.cpp para foo.mm (.mm é a extensão obj-c ++). Então, como outros disseram, a sintaxe padrão de mensagens obj-c funcionará.
fonte
Às vezes, renomear .cpp para .mm não é uma boa ideia, especialmente quando o projeto é multiplataforma. Neste caso, para o projeto xcode, eu abro o arquivo do projeto xcode através do TextEdit, encontrei uma string cujo conteúdo é o arquivo de interesse, deve ser assim:
e, em seguida, altere o tipo de arquivo de sourcecode.cpp.cpp para sourcecode.cpp.objcpp
É equivalente a renomear .cpp para .mm
fonte
Além disso, você pode chamar o tempo de execução Objective-C para chamar o método.
fonte
A resposta de @ DawidDrozd acima é excelente.
Eu acrescentaria um ponto. Versões recentes do compilador Clang reclamam da necessidade de um "elenco de ponte" ao tentar usar seu código.
Isso parece razoável: usar um trampolim cria um bug em potencial: como as classes Objective-C são contadas por referência, se passarmos seu endereço como um vazio *, corremos o risco de ter um ponteiro pendurado se a classe for coletada como lixo enquanto o retorno de chamada ainda está ativo.
Solução 1) Cocoa fornece funções de macro CFBridgingRetain e CFBridgingRelease que provavelmente adicionam e subtraem um da contagem de referência do objeto Objective-C. Devemos, portanto, ter cuidado com vários retornos de chamada, para liberar o mesmo número de vezes que retemos.
Solução 2) A alternativa é usar o equivalente a uma referência fraca (ou seja, nenhuma alteração na contagem de retenção), sem qualquer segurança adicional.
A linguagem Objective-C fornece o qualificador de conversão __bridge para fazer isso (CFBridgingRetain e CFBridgingRelease parecem ser wrappers Cocoa finos sobre as construções da linguagem Objective-C __bridge_retained e release respectivamente, mas Cocoa não parece ter um equivalente para __bridge).
As mudanças necessárias são:
fonte
self
para o encerramento, que pode ficar desatualizado. O outro ponto é que não está claro como isso interage com a contagem automática de referência e se o compilador pode descobrir o que está acontecendo. Na prática, não consegui criar uma situação em que nenhuma das versões falhasse em um exemplo simples de brinquedo de um módulo.Você pode misturar C ++ com Objectiv-C (Objective C ++). Escreva um método C ++ em sua classe Objective C ++ que simplesmente o chame
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
e chame de seu C ++.Não tentei antes, mas experimente e compartilhe os resultados conosco.
fonte