문제없이 클래스 EAGLView
의 멤버 함수를 호출 하는 클래스 ( )가 C++
있습니다. 이제 문제는 구문 에서 할 수없는 C++
클래스 a 를 호출해야한다는 것 입니다.objective-C
function
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
C++
이 Objective-C
호출을 Objective-C
처음에는 C ++ 클래스라고 부르는 동일한 클래스 로 래핑 할 수 있지만 어떻게 든에서 해당 메서드를 호출해야하는데 어떻게 C++
해야하는지 알 수 없습니다.
EAGLView
C ++ 멤버 함수에 대한 개체에 대한 포인터를 제공하고 클래스 헤더 EAGLView.h
에 ” “를 포함하려고 C++
했지만 3999 개의 오류가 발생했습니다.
그래서 .. 어떻게해야하나요? 예를 들어 보면 좋을 텐데 .. 나는 C
이것을하는 순수한 예 만을 찾았다 .
답변
신중하게 수행하면 C ++와 Objective-C를 혼합 할 수 있습니다. 몇 가지주의 사항이 있지만 일반적으로 혼합 할 수 있습니다. 별도로 유지하려면 Objective-C 개체에 비 Objective-C 코드에서 사용할 수있는 C 스타일 인터페이스를 제공하는 표준 C 래퍼 함수를 설정할 수 있습니다 (파일에 대해 더 나은 이름을 선택하고이 이름을 선택했습니다). 자세한 정보) :
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);
}
래퍼 기능 은 필요하지 않습니다.m
Objective-C 클래스 와 동일한 파일 에있을 존재하는 파일 은 Objective-C 코드로 컴파일해야합니다 . 래퍼 함수를 선언하는 헤더는 CPP 및 Objective-C 코드 모두에 포함되어야합니다.
(참고 : Objective-C 구현 파일에 “.m”확장자가 지정되면 Xcode 아래에 링크되지 않습니다. “.mm”확장자는 Objective-C와 C ++, 즉 Objective-C ++의 조합을 예상하도록 Xcode에 지시합니다. )
다음을 사용하여 객체 지향 방식으로 위를 구현할 수 있습니다. PIMPL 관용구 . 구현은 약간만 다릅니다. 간단히 말해서, MyClass의 인스턴스에 대한 (개인) void 포인터가있는 클래스 안에 래퍼 함수 ( “MyObject-C-Interface.h”에서 선언 됨)를 배치합니다.
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
래퍼 메서드는 더 이상 MyClass의 인스턴스에 대한 void 포인터를 필요로하지 않습니다. 이제 MyClassImpl의 개인 멤버입니다. init 메소드는 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
MyClass는 MyClassImpl :: init를 호출하여 인스턴스화됩니다. MyClassImpl의 생성자에서 MyClass를 인스턴스화 할 수 있지만 일반적으로 좋은 생각이 아닙니다. MyClass 인스턴스는 MyClassImpl의 소멸자에서 소멸됩니다. C 스타일 구현과 마찬가지로 래퍼 메서드는 단순히 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." );
}
}
이제 MyClassImpl의 개인 구현을 통해 MyClass에 대한 호출에 액세스합니다. 이 접근 방식은 휴대용 응용 프로그램을 개발하는 경우 유용 할 수 있습니다. MyClass의 구현을 다른 플랫폼에 특정한 구현으로 교체 할 수 있습니다.하지만 솔직히 이것이 더 나은 구현인지 여부는 취향과 필요의 문제입니다.
답변
코드를 Objective-C ++로 컴파일 할 수 있습니다. 가장 간단한 방법은 .cpp의 이름을 .mm로 바꾸는 것입니다. 그런 다음 포함하면 제대로 컴파일되고 EAGLView.h
(C ++ 컴파일러가 Objective-C 특정 키워드를 이해하지 못했기 때문에 너무 많은 오류가 발생 했음) Objective-C와 C ++를 혼합 할 수 있습니다 (대부분의 경우). 처럼.
답변
가장 쉬운 해결책은 Xcode에 모든 것을 Objective C ++로 컴파일하도록 지시하는 것입니다.
Compile Sources As to Objective C ++에 대한 프로젝트 또는 대상 설정을 설정하고 다시 컴파일하십시오.
그런 다음 어디에서나 C ++ 또는 Objective C를 사용할 수 있습니다. 예를 들면 다음과 같습니다.
void CPPObject::Function( ObjectiveCObject* context, NSView* view )
{
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)view.layer]
}
이는 모든 소스 파일의 이름을 .cpp 또는 .m에서 .mm로 변경하는 것과 동일한 영향을 미칩니다.
여기에는 두 가지 사소한 단점이 있습니다. clang은 C ++ 소스 코드를 분석 할 수 없습니다. 상대적으로 이상한 C 코드는 C ++에서 컴파일되지 않습니다.
답변
1 단계
객관적인 c 파일 (.m 파일)을 만들고 해당 헤더 파일입니다.
// 헤더 파일 ( “ObjCFunc.h”라고 함)
#ifndef test2_ObjCFunc_h
#define test2_ObjCFunc_h
@interface myClass :NSObject
-(void)hello:(int)num1;
@end
#endif
// 해당 Objective C 파일 ( “ObjCFunc.m”이라고 함)
#import <Foundation/Foundation.h>
#include "ObjCFunc.h"
@implementation myClass
//Your objective c code here....
-(void)hello:(int)num1
{
NSLog(@"Hello!!!!!!");
}
@end
2 단계
이제 방금 만든 목적 C 함수를 호출하는 C ++ 함수를 구현합니다! 이를 위해 .mm 파일을 정의하고 해당 헤더 파일 ( “.mm”파일이 여기에 사용됩니다. 파일에서 Objective C와 C ++ 코딩을 모두 사용할 수 있기 때문입니다)
// 헤더 파일 ( “ObjCCall.h”라고 함)
#ifndef __test2__ObjCCall__
#define __test2__ObjCCall__
#include <stdio.h>
class ObjCCall
{
public:
static void objectiveC_Call(); //We define a static method to call the function directly using the class_name
};
#endif /* defined(__test2__ObjCCall__) */
// 해당 Objective C ++ 파일 ( “ObjCCall.mm”이라고 함)
#include "ObjCCall.h"
#include "ObjCFunc.h"
void ObjCCall::objectiveC_Call()
{
//Objective C code calling.....
myClass *obj=[[myClass alloc]init]; //Allocating the new object for the objective C class we created
[obj hello:(100)]; //Calling the function we defined
}
3 단계
C ++ 함수 호출 (실제로 목적 C 메서드를 호출 함)
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
#include "ObjCCall.h"
class HelloWorld : public cocos2d::Layer
{
public:
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* createScene();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// a selector callback
void menuCloseCallback(cocos2d::Ref* pSender);
void ObCCall(); //definition
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld);
};
#endif // __HELLOWORLD_SCENE_H__
//최종 호출
#include "HelloWorldScene.h"
#include "ObjCCall.h"
USING_NS_CC;
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
/////////////////////////////
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.
// add a "close" icon to exit the progress. it's an autorelease object
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
origin.y + closeItem->getContentSize().height/2));
// create menu, it's an autorelease object
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);
/////////////////////////////
// 3. add your codes below...
// add a label shows "Hello World"
// create and initialize a label
auto label = Label::createWithTTF("Hello World", "fonts/Marker Felt.ttf", 24);
// position the label on the center of the screen
label->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - label- >getContentSize().height));
// add the label as a child to this layer
this->addChild(label, 1);
// add "HelloWorld" splash screen"
auto sprite = Sprite::create("HelloWorld.png");
// position the sprite on the center of the screen
sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
// add the sprite as a child to this layer
this->addChild(sprite, 0);
this->ObCCall(); //first call
return true;
}
void HelloWorld::ObCCall() //Definition
{
ObjCCall::objectiveC_Call(); //Final Call
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
return;
#endif
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
이것이 효과가 있기를 바랍니다!
답변
C ++ 파일을 Objective-C ++로 처리해야합니다. xcode에서 foo.cpp의 이름을 foo.mm로 변경하여이를 수행 할 수 있습니다 (.mm은 obj-c ++ 확장자 임). 그런 다음 다른 사람들이 표준 obj-c 메시징 구문이 작동한다고 말했듯이.
답변
특히 프로젝트가 크로스 플랫폼 인 경우 .cpp의 이름을 .mm로 바꾸는 것은 좋은 생각이 아닙니다. 이 경우 xcode 프로젝트의 경우 TextEdit를 통해 xcode 프로젝트 파일을 열고 내용에 관심이있는 파일 문자열을 찾았습니다.
/* OnlineManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OnlineManager.cpp; sourceTree = "<group>"; };
다음에서 파일 형식을 변경 sourcecode.cpp.cpp 에 sourcecode.cpp.objcpp
/* OnlineManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = **sourcecode.cpp.objcpp**; path = OnlineManager.cpp; sourceTree = "<group>"; };
.cpp의 이름을 .mm로 바꾸는 것과 같습니다.
답변
또한 Objective-C 런타임을 호출하여 메서드를 호출 할 수 있습니다.