Properly use Objective C++
ios, objective-c, objective-c++, xcode
Solution
Unfortunately, if you just start making classes `.mm`, any class that uses that `.mm`'s header will also need to become `.mm`. If you continue to just change your class extensions, you will eventually make the whole project Objective-c++. If that is your intention, then you can just change your build settings to compile for Objective-c++ (which could be a house of pain for you).
However, if you use some header magic, you will avoid a lot of hassle. Just make sure to change your `Compile sources as` build property to `According to file type` before compiling.
Here's something I did with a wrapper class I wrote to isolate a c++ class from the rest of my Objective-c classes. The c++ class is `MyClass`.
MyClassWrapper.h
//declare c++ impl for Obj-C++
#ifdef __cplusplus
class CppPlanterModel;
namespace com{namespace company{namespace mypackage {class MyClass;}}}
typedef com::company::mypackage::MyClass CppMyClass;
#endif
//declare obj-c impl
#ifdef __OBJC__
#ifndef __cplusplus
typedef void CppMyClass;
#endif
#endif
@interface MyClassWrapper : NSObject {
CppMyClass* _myClass;
}
//etc etc
@end
MyClassWrapper.mm
#include "MyClass.h"
using namespace com:company:mypackage;
class CppMyClass : public MyClass {
CppMyClass() {};
~CppMyClass() {};
//other stuff you might like to have
};
@implementation MyClassWrapper
//etc etc
@end
Here's another thing I did with a different header to handle sharing `extern` stuff:
Something.h
#ifdef __cplusplus
#define FV_EXTERN extern "C" __attribute__((visibility ("default")))
#else
#define FV_EXTERN extern __attribute__((visibility ("default")))
#endif
FV_EXTERN const int kMyInt;
FV_EXTERN int GetAnotherInt(...);
I recommend reading this blog entry about wrapping c++ (which also has links to other blog entries of a similar topic): http://robnapier.net/blog/wrapping-c-take-2-1-486
Problem
I'm coding an app for iOS and I recently #included a C++ header file in an Objective C implementation (.m) file. I changed the extension from .m to .mm and expected everything to run smoothly. Unexpectedly I got multiple compiler errors in the .h file of my C++ class. Such as: "C++ requires a type specifier for all declarations" and "Duplicate member...". Does anyone know what could be causing this? Edit - I've added the C++ header file for context: ``` #ifndef __CAAudioUnitOutputCapturer_h__ #define __CAAudioUnitOutputCapturer_h__ #include <AudioToolbox/ExtendedAudioFile.h> /* Class to capture output from an AudioUnit for analysis. example: CFURL fileurl = CFURLCreateWithFileSystemPath(NULL, CFSTR("/tmp/recording.caf"), kCFURLPOSIXPathStyle, false); CAAudioUnitOutputCapturer captor(someAU, fileurl, 'caff', anASBD); { captor.Start(); ... captor.Stop(); } // can repeat captor.Close(); // can be omitted; happens automatically from destructor */ class CAAudioUnitOutputCapturer { public: enum { noErr = 0 }; CAAudioUnitOutputCapturer(AudioUnit au, CFURLRef outputFileURL, AudioFileTypeID fileType, const AudioStreamBasicDescription &format, UInt32 busNumber = 0) : mFileOpen(false), mClientFormatSet(false), mAudioUnit(au), mExtAudioFile(NULL), mBusNumber (busNumber) { CFShow(outputFileURL); OSStatus err = ExtAudioFileCreateWithURL(outputFileURL, fileType, &format, NULL, kAudioFileFlags_EraseFile, &mExtAudioFile); if (!err) mFileOpen = true; } void Start() { if (mFileOpen) { if (!mClientFormatSet) { AudioStreamBasicDescription clientFormat; UInt32 size = sizeof(clientFormat); AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, mBusNumber, &clientFormat, &size); ExtAudioFileSetProperty(mExtAudioFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat); mClientFormatSet = true; } ExtAudioFileWriteAsync(mExtAudioFile, 0, NULL); // initialize async writes AudioUnitAddRenderNotify(mAudioUnit, RenderCallback, this); } } void Stop() { if (mFileOpen) AudioUnitRemoveRenderNotify(mAudioUnit, RenderCallback, this); } void Close() { if (mExtAudioFile) { ExtAudioFileDispose(mExtAudioFile); mExtAudioFile = NULL; } } ~CAAudioUnitOutputCapturer() { Close(); } private: static OSStatus RenderCallback( void * inRefCon, AudioUnitRenderActionFlags * ioActionFlags, const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) { if (*ioActionFlags & kAudioUnitRenderAction_PostRender) { CAAudioUnitOutputCapturer *This = (CAAudioUnitOutputCapturer *)inRefCon; static int TEMP_kAudioUnitRenderAction_PostRenderError = (1 << 8); if (This->mBusNumber == inBusNumber && !(*ioActionFlags & TEMP_kAudioUnitRenderAction_PostRenderError)) { OSStatus result = ExtAudioFileWriteAsync(This->mExtAudioFile, inNumberFrames, ioData); if (result) DebugMessageN1("ERROR WRITING FRAMES: %d\n", (int)result); } } return noErr; } bool mFileOpen; bool mClientFormatSet; AudioUnit mAudioUnit; ExtAudioFileRef mExtAudioFile; UInt32 mBusNumber; }; #endif // __CAAudioUnitOutputCapturer_h__ ```