8

I am trying to make a wrapper in Objective-C so I don't have to write c++ outside the library classes.

The Library main file is LLAHProcessor.h .cpp

My Wrapper is LLAHProcessorWrapper.h .mm

It compiles fine, but when I add LLAHProcessorWrapper to other class, (Lets say an UIView) as a member variable I get hundreds of errors, like:

#include <map> : Map no such a file or directory

and in every c++ class/struct:

Expected specifier-qualifier list before ClassName

Is like compiler is not recognizing c++ code.

I wonder what am I missing here. Does it has to be something with the fact I added this to Xcode Target Properties: ?

Other Link Flags : -lstdc++ -lz

Or maybe I need to add new flags here?

Thanks in advance

RedBlueThing
  • 42,006
  • 17
  • 96
  • 122
nacho4d
  • 43,720
  • 45
  • 157
  • 240
  • 1
    It's critical that `LLAHProcessorWrapper.h` contains no C++ code whatsoever. `LLAHProcessor.h` should be imported in your `.mm`. file, not in the `.h` file. Did you do that? – Ole Begemann Nov 17 '10 at 12:20
  • You also have .m files in the project? – Chris Becke Nov 17 '10 at 12:24
  • @Chris I have lots of .m files. This is quite a big program. – nacho4d Nov 17 '10 at 12:26
  • @Ole, Ok, I understand what you mean to say, but if I do that how I am supposed to have member variables? Should I just add them outside the methods implementation inside the LLAHProcessorWrapper.mm file? – nacho4d Nov 17 '10 at 12:28
  • Use `void *` pointers for instance variables. See PeyloW's answer. – Ole Begemann Nov 17 '10 at 12:57

3 Answers3

6

Your problem is that .m files are compiled as C instead of C++. Thus when the compiler comes across any C++ even in a header file while compiling a .m file, it will barf.

No doubt you have to put some C++ in your header file because your Objective C object wraps a C++ object, but there are ways around this. One way would be to use a pointer to the C++ object and make use of the handy preprocessor define __cplusplus which is defined for C++ (and Objective-C++) but not for C (or Objective-C) e.g.

// LLAHProcessorWrapper.h

#if defined __cplusplus
class MyCPPClass;    // forward class declaration
#else
typedef struct MyCPPClass MyCPPClass;   // forward struct declaration
#endif

@interface MyOCClass : NSObject
{
@private
    MyCPPClass* cppObject;
} 

// methods and properties

@end

Since you never dereference the members of the cppObject outside of the .mm file it doesn't matter that you never provide a full definition for the struct.

You would new and delete the pointer in -init and -dealloc respectively. You would include the full C++ class declaration in LLAHProcessorWrapper.mm.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • 1
    Incase this is of use to anyone: I got caught out by still having `#include "MyCPPClass.h"` in the `LLAHProcessorWrapper.h`. It should be in the `LLAHProcessorWrapper.mm` instead. – Ross May 20 '11 at 13:22
  • I guess we can now use class extentions as well ? perhaps a better approach ? – Ahmed Feb 10 '13 at 04:38
4

All you need to do is to create a .mm as you have done, and the compiler should take care of everything.

The caveat being that it is not safe to have anything C++ related in the .h files, since they can/will be imported by other Objective-C only files, and then everything breaks down. The main problem here is that you can not define C++ types directly as instance variables for your Objective-C wrapper class, unless every single .m file is renamed as a Objective-C++ .mm file.

The solution is to define the instance variables as void* in the header file, and access them with type casting from the implementation file. Easiest solution for this would be to access the instance variable using a private property that to the typecast for you.

Example code assuming Foo is a C++ class defined in Foo.h:

// FooWrapper.h
#import <Foundation/Foundation.h>

@interface FooWrapper : NSObject {
@private
  void* foo;
}
// Actual wrapper API for Foo…
@end


// FooWrapper.mm
#import "FooWrapper.h"
#include <map>
#include "Foo.h"

@interface FooWrapper ()
@property(nonatomic, assign) Foo* foo;
@end

@implementation FooWrapper
-(Foo*)foo {
  return (Foo*)foo;
}
-(void)setFoo:(Foo*)aFoo {
  foo = (void*)aFoo;
}
// Implementation of actual API for Foo…
@end
PeyloW
  • 36,742
  • 12
  • 80
  • 99
0

In any header (.h) file in which you want to refer to LLAHProcessorWrapper, use forward class definitions instead of imports, like so:

@class LLAHProcessorWrapper;
@interface SomeView : UIView {
  LLAHProcessorWrapper *wrapper;
}

and make sure that the corresponding implementation file has #include LLAHProcessorWrapper.h or #import LLAHProcessorWrapper.h.

Any implementation file in which you #include or #import your header must have .mm as its suffix if LLAHProcessorWrapper.h or anything else in the entire include tree has any C++ syntax at all. In this way, having one .mm file has a tendency to mean that huge portions of a codebase must have their files renamed to .mm.

Josh Bleecher Snyder
  • 8,262
  • 3
  • 35
  • 37