i have problem with calling some function in c++ from objective-c.
I have the following code. In "objCFuncA" how do i call "funcBCallback(std::string inText)" function?. Thanks
SampleCallback.h
class SampleCallback
{
public:
static void funcA();
static void funcBCallback(std::string inText);
};
SampleCallback.mm
void SampleCallback::funcA()
{
[[SampleCallback_iOS shared] objCFuncA:"My text from C++"];
}
void SampleCallback::funcBCallback(std::string inText)
{
NSLog(#"SUCCES GET RETURN");
}
SampleCallback_iOS.h
#interface SampleCallback_iOS : NSObject
+ (SampleCallback_iOS*)shared;
- (void)objCFuncA:(const char*)inString;
#end
SampleCallback_iOS.m
#implementation SampleCallback_iOS
static SampleCallback_iOS* instance = nil;
+ (SampleCallback_iOS*)shared
{
#synchronized(self) {
if (instance == nil) {
instance = [[self alloc] init];
}
}
return instance;
}
- (void)objCFuncA:(const char*)inString
{
NSLog(#"Text from C++: %s", inString);
// How to call SampleCallback::funcBCallback?
}
#end
It's not possible to call C++ functions from plain Objective-C (like you can't call C++ from plain C).
You can convert your Objective-C file to Objective-C++, though. To do so, just rename the file to use the extension .mm instead of .m.
Related
I hope someone can help me with my problem, searched long and didn't find a sufficent answer.
I'm using Objective-C++ to merge Objective C and C++ classes (since for my project i need to inherit classes from both languages). My main class is a Objective-C class and I have a small helper class in C++, which gets passed in the Objective-C object and calls functions of it.
My problem is that while this works, there is no deallocation (or deconstruction) happening. It seems that passing self in the Objective-C class init method to the C++ class creates some sort of memory lock or leak when I try to save the Objective-C object to a class variable in the C++ object.
I am using ARC.
Here is the sample code:
#import <Foundation/Foundation.h>
#interface MyObjCClass : NSObject
#end
int main(int argc, const char * argv[]) {
MyObjCClass *test = [[MyObjCClass alloc] init];
test = nil;
}
class MyCppClass {
public:
MyCppClass(void *test);
~MyCppClass();
private:
void testFunction();
MyObjCClass *myObjCObject;
};
MyCppClass::MyCppClass(void *test){
MyObjCClass *obj = (__bridge MyObjCClass *) test;
myObjCObject = obj; //when doing this, there is no more deallocation/deconstruction called
NSLog(#"constructing c++ class");
}
MyCppClass::~MyCppClass(){
NSLog(#"deconstructing c++ class");
}
#implementation MyObjCClass {
MyCppClass *myCppObject;
}
- (instancetype)init
{
if (self) {
NSLog(#"initializing ObjC class");
myCppObject = new MyCppClass((__bridge void *) self);
}
return self;
}
- (void)dealloc
{
delete myCppObject;
NSLog(#"deallocating ObjC class");
}
#end
In
MyCppClass::MyCppClass(void *test){
MyObjCClass *obj = (__bridge MyObjCClass *) test;
myObjCObject = obj; // <-- Creates a strong reference
NSLog(#"constructing c++ class");
}
a strong reference to the object is created, and that prevents the
object from being deallocated. A possible solution is to use
a weak reference instead:
class MyCppClass {
// ...
private:
void testFunction();
__weak MyObjCClass *myObjCObject; // <-- Weak reference
};
The weak pointer is set to nil when the object is deallocated.
For more information, see Use Weak References to Avoid Retain Cycles in the "Advanced Memory Management Programming Guide".
I'm attempting to modify a C++ class in such a way that an Objective C object is one of its instance variables.
In essence, this question is like the reverse of this: C++ classes as instance variables of an Objective-C class
The header file MyCPPClass.h looks like this:
namespace my_namespace{
class MyCPPClass: public my_namespace::OperationHandler {
public:
void someFunc();
private:
void otherFunc();
};
}
And the MyCPPClass.mm file looks like this:
#include "MyCPPClass.h"
#import <Foundation/Foundation.h>
void my_namespace:: MyCPPClass:: someFunc() {
NSLog(#"I can run ObjC here! Yahoo!");
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"download_url_goes_here"]];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// handle the data
}];
}
void my_namespace:: MyCPPClass:: otherFunc() {
NSLog(#"I can run ObjC here! Yahoo!");
}
The issue here is that I need to store a reference to an object created in someFunc() and then use it in otherFunc(). This object is an instance of NSURLSessionTask. My background in C++ is very limited :(. What is the least intrusive way to do this?
I believe you can store it as a void*, according to this Pass an Objective-C object to a function as a void * pointer
So your header would become:
namespace my_namespace{
class MyCPPClass: public my_namespace::OperationHandler {
public:
void someFunc();
private:
void otherFunc();
void *mySessionTask;
};
}
If you want to send a message to it you first cast it back to what it is supposed to be:
[(NSURLSessionTask*)mySessionTask someMessageWithArg: foo]
I use Wrapper-Class using pimpl so I can use Objective-C methods while using C++.
Now in my ViewWrapper.hpp I have this:
class ViewWrapper
{
public:
void addSubview(ViewWrapper *view); //method exists in original View.h (Objective-C)
ViewWrapper (void);
~ViewWrapper (void);
private:
struct Impl;
Impl* impl;
};
In my ViewWrapper.mm:
//ViewWrapper.mm
#import "ViewWrapper.hpp"
#import "View.h" // original Objective-C header
struct ViewWrapper::Impl
{
View* obj;
};
ViewWrapper::ViewWrapper() : impl(new Impl)
{
impl->obj = [[View alloc] init];
}
void ViewWrapper::addSubview(ViewWrapper *view)
{
[impl->obj addSubview:(View *) view]; // <- here is the error
}
Now in my main.cpp I use it like this:
// main.cpp
ViewWrapper *wrapper1 = new ViewWrapper();
ViewWrapper *wrapper2 = new ViewWrapper();
wrapper1->addSubview(wrapper2);
Now when I try to compile it, I get the error message
"Thread 1:EXC_BAD_ACCESS(code=2, address=0x105)" in my ViewWrapper.mm
I guess my problem is that this is not the correct way of casting ViewWrapper to View. Any other method works just fine (e.g. const char* to NSString and so on..)
Can anyone help me? If you need more info, I'll try to add it as good as I can.
I solved it myself. If anyone faces the same problem, I changed my addSubview-method like that:
[impl->obj addSubview:(UIView *) view->impl->obj];
I'm writing a game for the iPhone. Almost all the code is written in C++. Now I'd like to create a new thread using NSThread (I want to use the runLoop).
It's possible to mix objective-C and C++ if the code is written in a .mm file, which I did.
The problem is, that for creating a NSThread
NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:#selector(workerThreadFunction:) object:nil];
[myThread start];
I need to pass "self" which (as far as I understand it) an Objective-C "id" - and a c++ object is not an objective-c object.
So - is there a way to use NSThread in a c++ aplication or am I forced to use pthreads?
Thanks!
can I somehow create an objective-C object which - in it's constructor - takes a c++ function pointer as an argument which it calls later?
Sure. Like this:
//The C++ base
class ThreadBase
{
virtual void Run() = 0;
};
typedef ThreadBase * (*ThreadCreator)();
//The ObjC wrapper
#interface ThreadStarter:NSObject
{
ThreadCreator TheCreator;
}
-(void)Run;
-(id)init:(ThreadCreator)tc;
#end
#implementation ThreadStarter
-(id)init:(ThreadCreator)tc
{
TheCreator = tc;
return [super init];
}
-(void)Run
{
(*TheCreator)()->Run();
}
#end
//
class MyThread: public ThreadBase
{
//...
};
ThreadBase *MyThreadCreator()
{
return new MyThread();
}
//And finally usage
ThreadStarter *tc = [[ThreadStarter alloc]init:MyThreadCreator];
NSThread* myThread = [[NSThread alloc] initWithTarget:tc selector:#selector(Run) object:nil]; [myThread start];
It's parametrized by a creator function because you wanted it so. But you can parametrize by class as well.
"can I somehow create an objective-C object which - in it's constructor - takes a c++ function pointer as an argument which it calls later?"
Yes, but its rather ugly.
First, define a callback baseclass, and a templated version. This can go into a generic .h file that can be #included from .cpp and .mm files. Also define a basic CThread class:
// Thread.h
#pragma once
#include <objc/objc.h> // for a cpp compatible definition of id
class Callback{
public:
virtual void operator()(void)=0;
};
template<class T>
class ClassCallback : public Callback {
T* _classPtr;
typedef void(T::*fncb)(void);
fncb _cbProc;
public:
ClassCallback(T* classPtr,fncb cbProc):_classPtr(classPtr),_cbProc(cbProc){}
virtual void operator()(void){
(_classPtr->*_cbProc)();
}
};
class CThread {
id _thread;
public:
void Start(Callback* cb);
};
Next, put the implementation of CThread, and its obj-c buddy object, in a .mm file:
// Thread.mm
#import <Cocoa/Cocoa.h>
#import "Thread.h"
#interface ThreadStarter:NSObject
{
Callback *theCallback;
}
-(void)Run;
-(id)init:(Callback*)cb;
#end
#implementation ThreadStarter
-(id)init:(Callback*)cb
{
theCallback = cb;
return [super init];
}
-(void)Run
{
theCallback();
}
#end
void CThread::Start(Callback* cb){
_thread = [[ThreadStarter alloc] init:cb];
[NSThread detachNewThreadSelector:#selector(Run)
toTarget:_thread
withObject:nil];
}
};
And then, in your application's cpp file, you can:
// MyClass.cpp (doesn't even have to be .mm)
#include "Thread.h"
class MyClass {
CThread _myThread;
void SomeArbMethod(){
}
public:
MyClass(){
_myThread.Start( new ClassCallback<MyClass>(this,&MyClass::SomeArbMethod));
}
};
You cannot derive C++ classes from Objective C classes and vice versa. Design a wrapper ObjC object that would instantiate and call (but not inherit from) the C++ one. This is generally called "containment and delegation".
Or you can use POSIX threads instead of NSThread.
For a C++-style rephrasing of my previous answer:
//The C++ base
class ThreadBase
{
virtual void Run() = 0;
};
//The ObjC wrapper
#interface ThreadStarter:NSObject
{
ThreadBase *TheThread;
}
-(void)Run;
-(id)init:(ThreadBase)tb;
#end
#implementation ThreadStarter
-(id)init:(ThreadBase)tb
{
TheThread = tb;
return [super init];
}
-(void)Run
{
TheThread->Run();
}
#end
//
class MyThread: public ThreadBase
{
//...
};
//And finally usage
MyThread *Thread = new MyThread();
ThreadStarter *tc = [[ThreadStarter alloc]init:Thread];
NSThread* myThread = [[NSThread alloc] initWithTarget:tc selector:#selector(Run) object:nil];
[myThread start];
Much cleaner this way, IMHO. If you're insist that the thread start routine is an arbitrary function in an atrbitrary class not of your creation, here's your answer:
class MyThread: public ThreadBase, public MyOtherObject
{
void Run()
{
DoWork(); //Function defined in MyOtherObject
}
}
You see, if you want to parametrize by member function, you have to parametrize by both function and class. And class cannot be a run-time variable in C++.
I encountered following weird behavior yesterday. It seems a compiler bug to me or is there a something that I've missed? I was wrapping Facebook Connect for iPhone's Objective-C classes with Objective-C to C++ adaptor classes, so that they could be used from our own OpenGL/C++ code more conveniently.
The following code reveals the problem. In the first variant below, the compiler compiles but messes up the vtables and thus wrong method is called. In the second variant, we get a compiler error which indicates that gcc is confused.
Comments try to explain the situation in more detail.
#include <iostream>
#import <Foundation/Foundation.h>
// An abstract C++ interface
class Foo_cpp {
public:
virtual void foo() = 0;
};
// Another abstract C++ interface
class Bar_cpp {
public:
virtual void bar() = 0;
};
// An Objective-C to C++ adaptor.
// It takes a C++ interface Foo. When it's do_foo method is called it
// delegates call to Foo::foo.
#interface Foo_objc : NSObject {
Foo_cpp* foo_cpp_;
}
#end
#implementation Foo_objc
- (id)init:(Foo_cpp*)foo {
self = [super init];
if (self) {
foo_cpp_ = foo;
}
return self;
}
- (void) do_foo {
std::cout << "do_foo: ";
foo_cpp_->foo();
}
#end
// Another Objective-C to C++ adaptor.
#interface Bar_objc : NSObject{
Bar_cpp* bar_cpp_;
}
#end
#implementation Bar_objc
- (id)init:(Bar_cpp*)bar {
self = [super init];
if (self) {
bar_cpp_ = bar;
}
return self;
}
- (void) do_bar {
std::cout << "do_bar: ";
bar_cpp_->bar();
}
#end
// Main class implements both abstract C++ interfaces (which will
// confuse the compiler as we shall see).
// It constructs two Objective-C to C++ adaptors as a members and
// tries to pass itself as a C++ delegate for these adaptors.
class Main : public Foo_cpp, public Bar_cpp {
public:
Foo_objc* foo_;
Bar_objc* bar_;
Main() {
// We try to construct two objective-c to c++ adaptors Foo_objc and
// Bar_objc.
//
// We expect output of
// [foo_ do_foo];
// [bar_ do_bar];
// to be
// do_foo: foo
// do_bar: bar
#if 0
// This variant compiles but the compiler messes up
// the vtables. When do_bar() is called, we expect
// bar() to be called via Bar_objc, but instead
// foo() is called from both adaptors.
// Output is
// do_foo: foo
// do_bar: foo !!!! Calls wrong method !!!!
foo_ = [[Foo_objc alloc] init:this];
bar_ = [[Bar_objc alloc] init:this];
[foo_ do_foo];
[bar_ do_bar];
#else
// Now, this variant tries to help the compiler by passing
// |this| via a variable of the correct interface type.
// It actually reveals the confusion that the compiler
// is having. Seems like a bug in the compiler.
Foo_cpp* iface = this;
foo_ = [[Foo_objc alloc] init:iface];
Bar_cpp* iface2 = this;
// Error we get is on the next code line.
// $ g++ -x objective-c++ -lobjc mheritance_test.mm
// mheritance_test.mm: In constructor ‘Main::Main()’:
// mheritance_test.mm:107: error: cannot convert ‘Bar_cpp*’ to ‘Foo_cpp*’ in argument passing
bar_ = [[Bar_objc alloc] init:iface2];
[foo_ do_foo];
[bar_ do_bar];
#endif
}
~Main() {
delete foo_;
delete bar_;
}
virtual void foo() {
std::cout << "foo" << std::endl;
}
virtual void bar() {
std::cout << "bar" << std::endl;
}
};
int main() {
Main m;
}
The problem occurs with iPhone SDKs and Mac's own g++ and with versions 4.0.1 and 4.2.
Is there something I've understood incorrectly or is this a bug in g++?
UPDATE
My example contained an accidental bug pointed out Tyler and Martin York, but it isn't the problem here. Below is an updated example.
#include <iostream>
#import <Foundation/Foundation.h>
// An abstract C++ interface
class Foo_cpp {
public:
virtual void foo() = 0;
};
// Another abstract C++ interface
class Bar_cpp {
public:
virtual void bar() = 0;
};
// An Objective-C to C++ adaptor.
// It takes a C++ interface Foo. When it's do_foo method is called it
// delegates call to Foo::foo.
#interface Foo_objc : NSObject {
Foo_cpp* foo_cpp_;
}
#end
#implementation Foo_objc
- (id)init:(Foo_cpp*)foo {
self = [super init];
if (self) {
foo_cpp_ = foo;
}
return self;
}
- (void) do_foo {
std::cout << "do_foo: ";
foo_cpp_->foo();
}
#end
// Another Objective-C to C++ adaptor.
#interface Bar_objc : NSObject{
Bar_cpp* bar_cpp_;
}
#end
#implementation Bar_objc
- (id)init:(Bar_cpp*)bar {
self = [super init];
if (self) {
bar_cpp_ = bar;
}
return self;
}
- (void) do_bar {
std::cout << "do_bar: ";
bar_cpp_->bar();
}
#end
class Main : public Foo_cpp, public Bar_cpp {
void foo() {
std::cout << "foo" << std::endl;
}
void bar() {
std::cout << "bar" << std::endl;
}
};
int main() {
Main* m = new Main;
#if 0
// Compiles but produces
// do_foo: foo
// do_bar: foo !!! incorrect method called !!!
Foo_objc* fo = [[Foo_objc alloc] init:m];
Bar_objc* bo = [[Bar_objc alloc] init:m];
#else
// Doesn't compile
Foo_objc* fo = [[Foo_objc alloc] init:(Foo_cpp*)m];
Bar_objc* bo = [[Bar_objc alloc] init:(Bar_cpp*)m];
// A line above produces following error
// mheritance_test2.mm: In function ‘int main()’:
// mheritance_test2.mm:82: error: cannot convert ‘Bar_cpp*’ to ‘Foo_cpp*’ in argument passing
#endif
[fo do_foo];
[bo do_bar];
}
UPDATE 2
If init: methods of Fooobjc and Barobjc are renamed to initfoo: and initbar: then it works correctly, but I still can't explain what is the problem with the code. Could it be related how Objective-C creates a method signatures?
I'm editing out my hints on the answering, since I completed the mission ;-)
I am not an Objective-C programmer, but driven by curiosity I couldn't help wondering what's going on and played with the code a bit. What I've found out that the problem surfaces after commenting out everything but Foo* and Bar* parts and adding the following line to the main():
Bar_objc *bo = [[Bar_objc alloc] init:(Bar_cpp*)0];
After playing a bit I figured that it must have something to do with not quite defined result of the alloc message. Which is fixed by splitting the assignment above in two:
Bar_objc *bo = [Bar_objc alloc]; [bo init:(Bar_cpp*)0];
That works just fine. So does casting the alloc results (see the code below). Alternatively, this can be fixed (I believe) with different names for initializers. Maybe also reimplementing alloc. No idea.
The full code with multiple inheritance (it has some other minor changes - I've changed class/public pairs to structs for brevity, removed calling virtuals in constructors, changed delete invocations to dealloc messages, maybe something else):
#include <iostream>
#import <Foundation/Foundation.h>
struct Foo_cpp { virtual void foo() = 0; };
struct Bar_cpp { virtual void bar() = 0; };
#interface Foo_objc : NSObject {
Foo_cpp* foo_cpp_;
}
- (id)init:(Foo_cpp*)foo;
- (void)do_foo;
#end
#implementation Foo_objc : NSObject {
Foo_cpp* foo_cpp_;
}
- (id)init:(Foo_cpp*)foo {
if( self = [super init] ) foo_cpp_ = foo;
return self;
}
- (void) do_foo { std::cout << "do_foo: "; foo_cpp_->foo(); }
#end
#interface Bar_objc : NSObject {
Bar_cpp* bar_cpp_;
}
- (id)init:(Bar_cpp*)bar;
- (void)do_bar;
#end
#implementation Bar_objc : NSObject {
Bar_cpp* bar_cpp_;
}
- (id)init:(Bar_cpp*)bar {
if( self = [super init] ) bar_cpp_ = bar;
return self;
}
- (void) do_bar { std::cout << "do_bar: "; bar_cpp_->bar(); }
#end
struct Main : public Foo_cpp, public Bar_cpp {
Foo_objc* foo_;
Bar_objc* bar_;
Main() {
foo_ = [(Foo_objc*)[Foo_objc alloc] init:this];
bar_ = [(Bar_objc*)[Bar_objc alloc] init:this];
}
~Main() { [foo_ dealloc]; [bar_ dealloc]; }
virtual void foo() { std::cout << "foo" << std::endl; }
virtual void bar() { std::cout << "bar" << std::endl; }
};
int main() {
Main m;
[m.foo_ do_foo];
[m.bar_ do_bar];
}
The result:
do_foo: foo
do_bar: bar
The bottom line: I take it due to somewhat weak typing and possibility to send messages to the objects regardless of types, it's better to have no messages with the same name, but different parameters.
It is undefined behavior to call virtual methods from inside the constructor.
Since you are calling both foo() and bar() from Main() I would not expect you to have well defined output. But doing the calls after the object has been constructed should work. Try:
int main()
{
Main m;
[m.foo_ do_foo];
[m.bar_ do_bar];
}
A comment from Apple Developer forums explained the problem:
The problem is that you have multiple
methods call -init: that take
different parameter types. +alloc
returns (id), so the compiler has to
guess which -init: method to call. In
this case, it guesses wrong and passes
the wrong pointer to the
multiply-inherited object.
-Wstrict-selector-match will force a compiler warning, but the compiler
should have warned about the ambiguity
even without that option. You should
file a bug report.
One solution is
to rename your methods -initWithFoo:
and -initWithBar: to avoid the
confusion. Another solution is to
type-cast the result of +alloc before
calling -init:.
I'll mark #hacker's answer as a correct though, as it was correct. Knowing about -Wstrict-selector-match is a good additional info.
It's because you're trying to call virtual methods on an object before the constructor is done executing.
I did a test using your first method, just moving the
[foo_ do_foo];
[bar_ do_bar];
methods outside the constructor, and it worked for me.
Added This is basically item 9 from Scott Meyers' Effective C++:
Never call virtual functions during construction or destruction.
The Meyster would probably have a fit about your destructors being non-virtual as well (item 7).
Usually I get annoyed when people quote Meyers to me, but in this case I hope it's mostly helpful!