Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Properly use Objective C++

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__
like image 303
Orpheus Mercury Avatar asked May 03 '26 10:05

Orpheus Mercury


1 Answers

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

like image 110
Tim Reddy Avatar answered May 05 '26 00:05

Tim Reddy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!