How to include C++ headers in an Objective C++ header? - c++

I have a .cpp/.hpp file combo -> the .hpp file has #include ..
I also have a .mm/.h file combo -> if I include the .hpp file within my .mm Objective C++ file, there are no issues. However, if I try to include the .hpp file within my .h (Objective C header) file, I get a preprocessor issue 'iostream not found'.
Is there any way around this other than doing funky stuff like having a void* in my Objective C .h file and then casting it as the type that is included in the .mm or wrapping every C++ type within an Objective C++ type?
My question is basically the same as Tony's question (but nobody answered his):
https://stackoverflow.com/questions/10163322/how-to-include-c-header-file-in-objective-c-header-file

The problem is that you have to avoid all C++ semantics in the header to allow normal Objective-C classes to include it. This can be accomplished using opaque pointers.
CPPClass.h
class CPPClass
{
public:
int getNumber()
{
return 10;
}
};
ObjCPP.h
//Forward declare struct
struct CPPMembers;
#interface ObjCPP : NSObject
{
//opaque pointer to store cpp members
struct CPPMembers *_cppMembers;
}
#end
ObjCPP.mm
#import "ObjCPP.h"
#import "CPPClass.h"
struct CPPMembers {
CPPClass member1;
};
#implementation ObjCPP
- (id)init
{
self = [super init];
if (self) {
//Allocate storage for members
_cppMembers = new CPPMembers;
//usage
NSLog(#"%d", _cppMembers->member1.getNumber());
}
return self;
}
- (void)dealloc
{
//Free members even if ARC.
delete _cppMembers;
//If not ARC uncomment the following line
//[super dealloc];
}
#end

To use C++ in an Objective-C++ header file make sure to:
Have a .h/.mm couple (Objective-C++)
In the identity of your file, have the type set to Objective-C++ Source (it should be automatic)
Include the considered file only from Objective-C++ source files. This point is obvious but can be very quickly forgotten and hard to track down

The #include directive simply includes text; the only time Objective C will complain is if there is something in the include file that is not valid Objective C.
In your case, it gives you the answer; the iostream.h header file is not found in Objective C. Find where this file is referenced and remove the #include to it.

Related

How to expose an Objective-C++ class to swift without prototyping it in the .h file

I'm trying to use a C++ library in my Swift project and until now, it works fine, except that I have a little problem when I'm trying to include a .h that contains C++ code in a .h of one of my Objective-C++ .h file.
Here is the situation in picture :
Here is the .h of my Objective-C++ class. As you can see, the init method take in parameter a SuperpoweredAdvancedAudioPlayerCallback, this type is declared in the file SuperpoweredAdvancedAudioPlayer.h that is a file of the lib written in C++, so I include it.
But the problem is that I cannot include C++ code except in .mm file, otherwise, Xcode won't compile and says:
So I tried to move all the #interface block and the #import "SuperpoweredAdvancedAudioPlayer.h" of my SuperpoweredAdvancedAudioPlayerWrapped.h file in my .mm file but with that my SuperpoweredAdvancedAudioPlayerWrapped is not exposed to my Swift file, logic, the SuperpoweredAdvancedAudioPlayerWrapped.h file (that I include in file Bridging-Header) is now empty.
And if I only move the #import "SuperpoweredAdvancedAudioPlayer.h" in my .mm file, Xcode will not compile and says that SuperpoweredAdvancedAudioPlayerCallback is not a type, logic too...
So I'm stuck with that, as I'm not an Objective-C++ expert.
Any idea to solve this ?
The problem is that C++ types, such as SuperpoweredAdvancedAudioPlayer, cannot be exposed to Objective-C or Swift, but only to Objective-C++. Thus your wrapper, since it uses C++ classes, needs to be implemented in Objective-C++. The wrapper's header(s), i.e. the .h file(s), should not reference any C++ code.
I've seen a few uses of callbacks in the examples that come with Superpowered, and they typically implement the callbacks in Objective-C++ (.mm) files. You can search the code yourself, since it would not be very informative for the community to look at the product-specific examples.
What I might do in this case is
Not include the SuperpoweredAdvancedAudioPlayer.h header into the
header that declares the SuperpoweredAdvancedAudioPlayerWrapped
interface.
Express the interface in ..Wrapped.h in terms of custom data types
that will be implemented in .mm files, and that's where C++ code
will be referenced.
For example, you could introduce a SuperpoweredAdvancedAudioPlayerCallbackWrapped type that will be passed to the ..Wrapped init method.
The following is a mock-up example of how something like this could be done. First, here is some C++ code that we want to call from Swift (mylib.cpp):
#include "mylib.hpp"
MyCpp::MyCpp(MyCppCallback cb, int i) : m_CB(cb), m_Int(i) {}
int MyCpp::f(int i)
{
return m_CB(i + m_Int);
}
and the corresponding header file (mylib.hpp):
#ifndef mylib_hpp
#define mylib_hpp
/**
* Callback type used by the C++ code.
*/
typedef int (*MyCppCallback) (int);
/**
* A simple C++ class.
*/
class MyCpp
{
public:
MyCpp(MyCppCallback, int);
int f(int);
private:
MyCppCallback m_CB;
int m_Int;
};
#endif /* mylib_hpp */
The header, mylib.hpp, cannot be included in a Swift bridging header directly or indirectly, so we need a wrapper. BTW, the extension could be .h instead of .hpp, it doesn't really matter.
The wrapper code has to be Objective-C++ because it utilizes a C++ type (MyCpp), here it is (wrapper.mm):
#import "mylib.hpp"
#import "wrapper.h"
#implementation MyWrapper
{
MyCpp * pMyCpp;
}
-(id)init: (wrapper_cb_t)cb withInt: (int)i
{
pMyCpp = new MyCpp( cb, i );
return self;
}
-(int)f: (int)i
{
return pMyCpp->f(i);
}
#end
And here is the corresponding header, wrapper.h, that can be included in a Swift bridging header because it is free of any C++ stuff:
#ifndef wrapper_h
#define wrapper_h
#import <Foundation/Foundation.h>
/**
* Here we just repeat the callback typedef from mylib.hpp. We can do this because
* it does not depend on C++ types. If it did, we could come up with some
* "glue" code in wrapper.mm.
*/
typedef int (*wrapper_cb_t) (int);
/**
* This is the wrapper interface. It doesn't depend on any C++ types.
*/
#interface MyWrapper : NSObject
-(id)init: (wrapper_cb_t)cb withInt: (int)i;
-(int)f: (int)i;
#end
#endif /* wrapper_h */
The bridging header looks like this:
#import "wrapper.h"
and here is sample Swift code using the C++ code via the wrapper:
/**
* This is a Swift callback function of type wrapper_cb_t.
* To figure out how the wrapper's signature is imported into Swift,
* just type "wrapper_cb_t" somewhere in the code, click on it, and
* Xcode Quick Help should show you the signature.
*/
func swift_cb(i: Int32) -> Int32
{
return i + 111
}
/**
* Now create an instance of MyWrapper...
*/
let w : MyWrapper = MyWrapper(swift_cb, withInt: 3)
/**
* ... and use it:
*/
print("f() in the wrapper returned \(w.f(4))")
This sample is a very simplified piece of code and doesn't claim to be production quality. E.g., memory management is not covered.
Please note that once you start dealing with callbacks, things get a lot more complicated than just having Swift call Objective-C/C++ code. Now you have to write code that will be called by C and/or C++. You will find a lot of interesting info on that if you search for "Swift callback c" in this forum or Google.

I need help mixing C++ code and Objective-C code

I am writing a device driver for a Blackmagic Design AV device in XCode, and I'm having trouble including BMD's SyncController class from their abbreviated sample code (below) into my purely Objective-C project.
Their DecklinkAPI.h file is rich in C++ code, so when I try include this header file as-is in a an Objective-C class, the compiler chokes deep in the API include: Unknown type name 'class'; did you mean 'Class'?
I have tried to to bundle up the C++ bits into a Obj-C class extension as noted here, but without much success. I've never done any C++ programming (and have never used Obj-C class extensions), so this is new territory for me.
I'm not sure if I need to create an additional wrapper class for my SyncController object, or whether I can just do a class extension on this one and shuffle the C++ bits into the .mm file.
I would like to be able to do a #include "SyncController.h" (or its wrapper) in an Objective-C class without having the compiler choke.
Any assistance in doing so would be much appreciated.
First up, here is my current SyncController.h file:
#import <Cocoa/Cocoa.h>
#import "DeckLinkAPI.h" // this is rich in C++ code
class PlaybackDelegate;
#interface SyncController : NSObject {
PlaybackDelegate* playerDelegate;
IDeckLink* deckLink;
IDeckLinkOutput* deckLinkOutput;
}
- (void)scheduleNextFrame:(BOOL)prerolling;
- (void)writeNextAudioSamples;
#end
class PlaybackDelegate : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback
{
SyncController* mController;
IDeckLinkOutput* mDeckLinkOutput;
public:
PlaybackDelegate (SyncController* owner, IDeckLinkOutput* deckLinkOutput);
// IUnknown needs only a dummy implementation
virtual HRESULT QueryInterface (REFIID iid, LPVOID *ppv) {return E_NOINTERFACE;}
virtual ULONG AddRef () {return 1;}
virtual ULONG Release () {return 1;}
virtual HRESULT ScheduledFrameCompleted (IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result);
virtual HRESULT ScheduledPlaybackHasStopped ();
virtual HRESULT RenderAudioSamples (bool preroll);
};
void ScheduleNextVideoFrame (void);
Next up, here is my (simplified) SyncController.mm file:
#import <CoreFoundation/CFString.h>
#import "SyncController.h"
#implementation SyncController
- (instancetype)init
{
self = [super init];
return self;
}
- (void)dealloc
{
}
- (void)scheduleNextFrame:(BOOL)prerolling
{
}
- (void)writeNextAudioSamples
{
}
#end
PlaybackDelegate::PlaybackDelegate (SyncController* owner, IDeckLinkOutput* deckLinkOutput)
{
mController = owner;
mDeckLinkOutput = deckLinkOutput;
}
HRESULT PlaybackDelegate::ScheduledFrameCompleted (IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result)
{
[mController scheduleNextFrame:NO];
return S_OK;
}
HRESULT PlaybackDelegate::ScheduledPlaybackHasStopped ()
{
return S_OK;
}
HRESULT PlaybackDelegate::RenderAudioSamples (bool preroll)
{
[mController writeNextAudioSamples];
if (preroll)
mDeckLinkOutput->StartScheduledPlayback(0, 100, 1.0);
return S_OK;
}
I have tried to to bundle up the C++ bits into a Obj-C class extension as noted here, but without much success.
If you're targeting 64-bit, the class extension method should be fairly simple.
The following is equivalent to the code you've post, but moves all of the C++ declarations to a separate header:
SyncController.h:
#import <Cocoa/Cocoa.h>
#interface SyncController : NSObject
- (void)scheduleNextFrame:(BOOL)prerolling;
- (void)writeNextAudioSamples;
#end
SyncController_CPP.h
#import "SyncController.h"
#include "DeckLinkAPI.h"
class PlaybackDelegate;
#interface SyncController() {
PlaybackDelegate* playerDelegate;
IDeckLink* deckLink;
IDeckLinkOutput* deckLinkOutput;
}
#end
class PlaybackDelegate ...
{
...
}
SyncController.mm
#import "SyncController_CPP.h"
#implementation SyncController
...
#end
PlaybackDelegate::PlaybackDelegate (SyncController* owner, IDeckLinkOutput* deckLinkOutput)
{
mController = owner;
mDeckLinkOutput = deckLinkOutput;
}
// etc..
Any other ObjC classes that need access to SyncController will import "SyncController.h". Any other ObjC++ classes can import either "SyncController.h" or "SyncController_CPP.h"
Not a complete answer, however errors like:
Unknown type name 'class'; did you mean 'Class'?
Is a classic issue with Objective-C++ where an Objective-C implementation file is seeing a C++ header file.
I can only provide advice about how to avoid it as you didn't post the complete build output.
Don't put C++ headers is the pre-compiled header.
Try to only include C++ headers within Objective-C++ implementation files and not in their counterpart header file which might, in turn, be included into an Objective-C file.
Hide the use of C++ from any header files, for example using private instance variables:
#import <vector>
#implementation MyObjCppClass {
std::vector<int> _stuff;
}
- (id)init {
...
}
#end
If you are mixing Objective-C and Objective-C++ then you might find you need to provide Objective-C wrappers to C++ classes (which look from the outside as Objective-C but are actually implemented in Objective-C++).
Rename your .m files (objective-c) to .mm (objective-c++). this should allow you to then mix objc and c++ by including c++ headers and referencing c++ code from your objc.
---EDIT---
Any header file you include from objective-c must contain only objective-c. Remove any c++ from the header in your wrapper class to get the other objc classes to build. In modern objc, you can split your ivars between the .h and .m files; keep all your methods in the .h for other objc classes to use, and declare your c++ ivars in the .mm. Stick your c++ delegate class in its own .h that is only included from the .mm wrapper.
Use #if __cplusplus.
For example,
#import <Cocoa/Cocoa.h>
#if __cplusplus
#import "DeckLinkAPI.h" // this is rich in C++ code
#endif // __cplusplus
#interface SyncController : NSObject {
void* playerDelegate; // should be cast as C++ PlaybackDelegate class.
...
}
#end
#if __cplusplus
class PlaybackDelegate : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback
{
...
};
#endif // __cplusplus
The header file can be used with Objective-C and Objective-C++. But you can not use C++ class signature in SyncController Objective-C class declaration in the header. Use void * instead of PlaybackDelegate * with proper type cast.
Also using void * means that C++ stuff in the header is no longer needed.
#import <Cocoa/Cocoa.h>
#interface SyncController : NSObject {
void* playerDelegate; // should be cast as C++ PlaybackDelegate class.
...
}
#end
In Objective-C++ code,
// initialize
syncController.playerDelegate = new PlaybackDelegate();
// use the pointer
PlaybackDelegate *playbackDelegate = (PlaybackDelegate *)syncController.playerDelegate;
initialize
syncController.playerDelegate = new PlaybackDelegate();
// use the pointer
PlaybackDelegate *playbackDelegate = (PlaybackDelegate *)syncController.playerDelegate

Forward declaring a C++ class in Objective-C

I am writing an Objective-C class that needs to make function calls on a C++ class instance. I found this suggestion, but if I try it I get an error for having an incomplete definition of type 'struct MyCPlusPlusClass'
struct MyCPlusPlusClass;
typedef struct MyCPlusPlusClass MyCPlusPlusClass;
#interface MyBridgeClass() {
MyCPlusPlusClass *my_CPlusPlus;
}
...
- (id)initWithMrGame:(MyCPlusPlusClass *)cPlusPlus
{
self = [super init];
if (self) {
my_CPlusPlus = cPlusPlusClass;
my_CPlusPlus->p_favorite_integer = 0; // Compiler error
}
return self;
}
The actual definition occurs in a .mm file that's generated by a pre-compiler, just to add another layer of challenge.
How might I get this to work?
EDIT: Interpreting Adam's answer
// in MyCode.h
struct MyCPlusPlusClass; // Forward declaration, no need for #include/#import
#interface MyBridgeClass() {
struct MyCPlusPlusClass *my_CPlusPlus;
}
// in MyCode.m
#include MyCode.h
// in BigGenerateFile.mm
class MyCPlusPlusClass;
class MyCPlusPlusClass { ... }
My goal is to be able to use MyCPlusPlusClass in MyCode.m, but I can't include the .mm file because the compiler gets very unhappy. It may be that the way this thing is architected is going to make me go a different route.
You can't access member variables of incomplete structures/classes. To do so, you need to the full definition. Typically you use forward declarations in header files so that anything that includes that header doesn't pull in lots of unnecessary other header files it won't need, but for source files you usually need the full definitions.
So I'd suggest changing you code to something like this:
// Header file (.h)
struct MyCPlusPlusClass; // Forward declaration, no need for #include/#import
#interface MyBridgeClass() {
struct MyCPlusPlusClass *my_CPlusPlus;
}
// Source file (.mm)
#include "MyCPlusPlusClass.h"
...
// Can now access my_CPlusPlus->p_favorite_integer etc.
You can do a number of things on an incomplete type, but accessing members of an object of that type is not one of them.
A simple possible solution would be a helper function that's defined somewhere where the complete type is available:
void set_p_favorite_integer(MyCPlusPlusClass*, int);
// ...
set_p_favorite_integer(my_CPlusPlus, 0);

How to use an NSInteger in a c-style class declaration

I have a c-style class declaration:
#pragma once
class CSound
{
private:
NSInteger bufferID;
public:
CSound(const char* fileName);
~CSound();
static void init();
void play();
};
The compiler says NSInteger does not name a type.
If I put the "NSInteger bufferID;" in the .mm file (not in the .h) it works. What am I doing wrong?
EDIT
As I still have no solution, I did a quick dirty-ugly-fix:
in .h file, in the class definition
void* pBufferID;
and in the .mm file
// constructor
pBufferID = new NSUInteger;
// destructor
delete (NSUInteger*)pBufferID;
// everywhere I use it
*((NSUInteger*)pBufferID)
You're not including the header that defines NSInteger from your own header file (probably Foundation.h). Presumably you are doing so in your .mm file. Just move that #import or #include directive into your header.
Do you have the:
#import <UIKit/UIKit.h> (iOS)
or
#import <Cocoa/Cocoa.h> (Mac OS)
..imported at the top of your .h file?
And are you sure you have all the frameworks linked to your project?
foundation.framework
appKit.framework
UIKit.framework

Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link?

I have a small C++ application which I imported Objective-C classes. It works as Objective-C++ files, .mm, but any C++ file that includes a header which may end up including some Objective-C header must be renamed to a .mm extension for the proper GCC drivers.
Is there a way to write either a purely C++ wrapper for Objective-C classes or can I separate the Objective-C objects out somehow and just link them separately? Maybe even if the Objective-C classes became a small library I could statically re-link at compile time?
The problem is that this code is cross-platform, and it is more difficult to compile on systems that normally do not use Objective-C (i.e. not Macs). Even though preprocessor commands restrict any implementation of Objective-C code on Windows or Linux, the original code still has .mm extensions and GCC still treats the code as Objective-C++.
Usually you simply wrap your Objective-C classes with C++ classes by e.g. using opaque pointers and forwarding calls to C++ methods to Objective-C methods.
That way your portable C++ sources never have to see any Objective-C includes and ideally you only have to swap out the implementation files for the wrappers on different platforms.
Example:
// c++ header:
class Wrapper {
struct Opaque;
Opaque* opaque;
// ...
public:
void f();
};
// Objective-C++ source on Mac:
struct Wrapper::Opaque {
id contained;
// ...
};
void Wrapper::f() {
[opaque->contained f];
}
// ...
Yes, that's easily possible, both ways, if you know a few tricks:
1) The "id" type is actually defined in a plain C header. So you can do the following:
In your header:
#include <objc/objc.h>
class MyWindow
{
public:
MyWindow();
~MyWindow();
protected:
id mCocoaWindow;
};
In your implementation (.mm):
#include "MyWindow.h"
#include <Cocoa/Cocoa.h>
MyWindow::MyWindow()
{
mCocoaWindow = [[NSWindow alloc] init];
}
MyWindow::~MyWindow()
{
[mCocoaWindow release];
mCocoaWindow = nil;
}
2) There are two preprocessor constants you can use to exclude C++/ObjC-specific code when a source file includes them that is one of the two, but not ObjC++:
#if __OBJC__
// ObjC code goes here.
#endif /* __OBJC__*/
#if __cplusplus
// C++ code goes here.
#endif
Just be careful, you can't just add/remove ivars or virtual methods with an #ifdef, that will create two classes with different memory layouts and make your app crash in very weird ways.
3) You can use a pointer to a struct without declaring its contents:
In your header:
#interface MyCppObjectWrapper : NSObject
{
struct MyCppObjectWrapperIVars *ivars; // This is straight ObjC, no ++.
}
#end
In your implementation file (.mm):
struct MyCppObjectWrapperIVars
{
std::string myCppString1;
std::string myCppString2;
std::string myCppString3;
};
#implementation MyCppObjectWrapper
-(id) init
{
if(( self = [super init] ))
{
ivars = new MyCppObjectWrapperIVars;
}
return self;
}
-(void) dealloc
{
delete ivars;
ivars = NULL;
[super dealloc];
}
#end
This will make your header simple standard C or ObjC, while your implementation file gets constructors/destructors of all ivars called without you having to create/delete each one as an object on the heap.
This is all only the Mac side of things, but this would mean that you could keep the ObjC stuff out of your headers, or at least make it compile when used from cross-platform client files of the Mac implementation of your C++ portability layer.