How to Separate C++ Main Function and Classes from Objective-C And/Or C Routines at Compile and Link

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

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];
}

// ...

How to call C++ method from Objective-C Cocoa Interface using Objective-C++

I found a solution by noting that there was an existing wrapper class CWrapper.h and it was an objective-C++ implementation class CWrapper.mm. There was a CMain variable instantiated as cmain. I made a getter method for x and I simply created a static method in the wrapper class + (void) passX:(int) number; that I called in the slider class. I chose a static method because this for this application, this value will never have to be different between objects. I hope I made the right choice here!

See code changes below:

I added this to the Slider.h file.

- (int)X;

I added the getter and [CWrapper passX:[self getX]]; to the updateSliderValue method in the Slider.mm file.

- (int)X {
return [slider intValue];
}

- (IBAction)updateSliderValue:(id)sender {
[sliderValue setIntValue:[slider intValue]];
[CWrapper passX:[self getX]];
}

This is the code I added to CWrapper.h.

+ (void) passX:(int) number;

This is the code I added to CWrapper.mm.

+ (void) passX:(int)num
{
cmain.setValueofX(num);
}

Moving functions to separate classes

If you are wondering were to put C functions like the one you are describing, the best practice is to move them into a separate .h file that has a meaningful name. For instance MyGeometry.h

Make sure you give a descriptive name to your function, such as:

static inline CGPoint CGPointMakeRandom() {
// your code
return point;
}

How to handle objective-c delegation from C++?

Ok to answer your question:

reportwindow.h is additionally included in a .cpp file, if that makes
a difference.

It does make a difference. Any compilation unit (cpp file in this case) that is touching Objective-C code has to be renamed to .mm or .m. Including the header that in turn is including Objective-C stuff in a C++ file will lead to the problem that the C++ compiler sees Objective-C code which it cannot handle.

Renaming the cpp file to mm will select the Objective-C option during compilation (which isn't when the file is named cpp or c) and hence allow to compile stuff with the Objective-C tokens (mainly "@" in your case).

An alternative would be not to include the Objective-C delegate class to your C++ class but rather include a pointer to your C++ class within the Objective-C delegate (i.e. implement it the other way around). This way you could arrange things such that the Objective-C code isn't touching the C++ code.

Edit: Actually, I'd prefer the second suggestion. Here is an example:

DelegateClass.h:

class MyCPPClassHandlingStuff;

@interface MyDelegateObject : NSObject <SomeDelegateProtocol> {
MyCPPClassHandlingStuff *m_handlerInstance;
}

- (id) initWithCPPInstance:(MyCPPClassHandlingStuff*)cppInstance;

- (void) theDelegateProtocolMethod;

@end

DelegateClass.mm

#include "MyCPPClassHandlingStuff.h"

@implementation MyDelegateObject

- (id) initWithCPPInstance:(MyCPPClassHandlingStuff*)cppInstance
{
self = [super init];
if (self) {
m_handlerInstance = cppInstance;
}
return self;
}

- (void) theDelegateProtocolMethod
{
if (m_handlerInstance)
m_handlerInstance->handleDelegateMethod();
}

@end

And well the MyCPPClassHandlingStuff.h:

#ifndef __MyCPPClassHandlingStuff_H__
#define __MyCPPClassHandlingStuff_H__

class MyCPPClassHandlingStuff
{
public:
MyCPPClassHandlingStuff();
void handleDelegateMethod();
};

#endif /* __MyCPPClassHandlingStuff_H__ */

MyCPPClassHandlingStuff can be initialized from Objective-C but you cannot initialise any Objective-C class from C++ code there. If you need to use Objective-C in your C++ code, you would have to compile it as Objective-C (i.e. use an .mm file). I leave the .cpp details as an exercise for the reader ;)

Objective C Class Methods vs C Functions

In short, C (or C++) implementations are very useful:

  • For Abstraction
  • For Reusability
  • When making medium and large scale programs
  • In performance critical paths
  • For 'Interior' implementations

What benefit exists (other than coding style) for favouring a C function over a class method?

  • ObjC messaging introduces indirect function calls. These are firewalls for optimizers.
  • C functions can easily restrict access, whereas 'private' ObjC implementations may be looked up using the ObjC runtime, or accidentally overridden.
  • C functions may be removed from your executable if not referenced, or they may be made private. If you write reusable code (and you should), this can have a huge impact on your binary sizes and load times -- C functions which are not referenced/used may be removed, but ObjC types and methods will be preserved (including everything they reference). This is why your app's binary size may grow significantly when you use only small part of an ObjC static library -- every objc class in the library is preserved. If that library were C or C++, then you could get by with very small growth because you need only what is referenced. What is or is not referenced is easier to prove with C and C++.
  • C functions can be inlined, either during compilation or during Link Time Optimization phases.
  • The compiler and optimizers are able to do much optimization with C functions (e.g. inter-procedural optimizations), but very little with ObjC methods because they are always indirect.
  • To avoid ObjC message dispatch overhead (as you mentioned)
  • Potential for additional reference counting operations and autorelease pool activity when interacting with ObjC objects.

Of course you won't always hurt paying for things you don't need or use -- and remember that ObjC class methods have some benefits over C functions, too. So, just look at C or C++ implementations as another tool in your toolbox. I find them very useful as complexity and project sizes increase, and they can be used to make your programs much faster. Just do what you are least likely to regret in 2015 ;)

How to write objective c wrapper for c++ methods?

You should read up on "compilation units". In short, there's no way to tell what language a header file is written in for the compiler. Therefore, it always uses the language of the source file that includes the header. So if you include a C++ header from a .m file, it will not work. For every ObjC file that uses a C++ header, you have to change the file name suffix of the source file that uses it from .m to .mm. You do not need the source files for your rubberband library, you simply need to make all the files that use it ObjC++ instead of just ObjC.

Of course, you may not want to change all your files to be ObjC++. Your code for the alternate approach of wrappering the C++ is pretty close. One thing I noticed is that you still have the <#foo#> placeholders in your code (Xcode may display them as blue rounded cartouches, which is probably why you haven't noticed them before). Replace those with the actual names of the parameter variables, just like you would with a regular C function call, and all should compile. I.e.:

-(void)process:(const float)input samples:(size_t)samples final:(bool)final {
static_cast<RubberBand::RubberBandStretcher *>(myRubberBandStretcher)->process( input, samples, final );
}

Also note that you seem to have omitted the semicolon after the process call.

BTW, you can also get rid of having to use static_cast everywhere, see the tricks listed here: Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link? and there might also be some more useful info here: How to call C++ method from Objective-C Cocoa Interface using Objective-C++

Recommend way to use a large C++ library in a Cocoa application?

You can easily mix C++ and Objective-C using Objective-C++. In XCode just rename your .m files to .mm and it will recognize the files as Objective-C++. Then you can use the C++ classes in your Objective-C code (some restrictions apply, but not many).

Since Objective-C is an extension to C you can use C libraries in any Objective-C program easily.

How to wrap a C++ lib in objective-C?

My recommendation is to wrap the C++ bits in #ifdefs:

//MyWrapper.h

#ifdef __cplusplus
class ComposedClass;
#endif

@interface MyWrapper : NSObject
{
#ifdef __cplusplus
ComposedClass *ptr;
#endif
}

// wrapped methods here...
@end

This is a slightly lame version of the PIMPL idiom, but less code, and effective for hiding C++-isms from your pure Objective-C code. Obvioulsy you would have to include the ComposedClass's header in your MyWrapper.mm.

If ComposedClass is a templated type, you will need to modify the first block to

#ifdef __cplusplus
#include "ComposedClass.h"
#endif

instead of using a forward declaration and then, of course, use the templated type in your Objective-C class' instance variable declaration.

This approach was suggested by Greg Parker, the runtime guru at Apple.



Related Topics



Leave a reply



Submit