Using C++ class in Objective-C - Why use PImpl idiom? - c++

Suppose I have a simple C++ class:
// MyCPPClass.hpp
class MyCPPClass {
std::uint8_t m_num1 = 0;
std::uint8_t m_num2 = 0;
std::string GetText() const;
}
and I want to use this in an Objective-C class:
// MyObjCClass.h
#interface MyObjCClass {
#public
MyCPPClass _cppObj;
}
What do I really gain from using PImpl idiom over just embedding it directly into the Obj-C class (as above), aside from having to write more code for the PImpl part ?

The downside is this C++ type MyCPPClass is now in the header file MyObjCClass.h, which other Objective-C classes that use MyObjCClass will have to import. Importing a header is like putting it into the code, so these other Objective-C classes now have C++ in their code, and so will now have to be changed to Objective-C++ files or they won't compile. This is often not desirable, as these other files shouldn't need C++. Although this problem can be solved by declaring your instance variable not in the main class declaration in the header, but in the "extension" (declared like a category but with no name in the parentheses) or in the #implementation, which are in the implementation file, so other classes don't have to import it.
Another problem with C++ classes as instance variables of Objective-C classes is that your C++ object can only be constructed using the default constructor (i.e. no constructor arguments), as there is no way to provide an initializer for an instance variable of an Objective-C class. So if you want to construct it with constructor arguments, you must use pimpl.

Related

Writing a wrapper for a C++ Factory class for use in Objective-C

I have a factory class in C++ that I need to make use of in an Objective-C project, so I am trying to write a wrapper for it.
Below is the superclass definition of the Widget class.
class Widget
{
public:
Widget();
virtual ~Widget();
virtual Thingamajig getThingamajig() = 0;
};
The factory will return a subclass of Widget, and the Objective-C program will use the Thingamajig provided by Widget (I omitted details on Thingamajig-just presume it is a very simple data container class).
Here's the factory class:
class WidgetFactory
{
public:
/*...a series of integer constants defining the different types of widgets to be returned by
createWidget function below.*/
WidgetFactory();
~WidgetFactory();
Widget* createWidget( int type );
};
Because I am writing a wrapper, the createWidget method in the factory class is non-static (createWidget was originally static).
Now, here is what I have for the Objective-C wrapper thus far. It is the header for an Objective-C++ (mm file):
#interface WidgetFactoryWrapper: NSObject
#end
#interface WidgetFactoryWrapper()
-(Widget*) createWidget: (int)type;
#end
Here are my questions:
1) I got the idea of writing the wrapper like this from another SO article here (Calling C++ from Objective-C). However, I do not think the last step of writing something like CplusplusMMClass, another Objective-C++ class that uses the Objective-C++ wrapper, is necessary here-I should just call the Objective-C++ wrapper here directly. Is my thinking incorrect?
2) While I accept that I will have to write a wrapper around Widget, will I have to do so for all its subclasses?
3) If you were in my proverbial shoes, how would you go about doing this?
I'm tempted to just translate everything into Objective-C, but I want to be able to reuse what's already been written in C++.

How to pass a callback function from C++ to Objective-C

I don't want to use NSNotification because it is so messing up internally. Is it a way to pass a callback function from C++ to Objective-C++, and let Objective-C call it?
The problem is that I don't know how to pass a function written in C++ to Objective-C++, and how could I use that callback in Objective-C++? Is it a pointer?
I know I can mix them up but my class has to be a C++ class because it inherits some C++ classes.
You're not 100% specific as to the exact use case you're trying to cover here, but I'm going to set out a scenario where this kind of situation occurs, and then show you how to solve it. I hope that will cover your problem too.
So I'm going to assume you have an Objective-C class MyClass with its interface declared in MyClass.h:
#interface MyClass : NSObject
- (void)someMethod;
- (void)otherMethodWhichShouldTakeACallback:?????;
#end
You now have a C++ class MyCPPClass, declared in MyCPPClass.hpp on which you want to pass memberFunction as the callback argument to the otherMethod on MyClass:
class MyCPPClass : public MyBase
{
void memberFunction();
};
First, we need to figure out the method signature on MyClass. The modern way for callbacks in Objective-C is with Blocks. Blocks work pretty well with Objective-C++, so let's go with that and modify MyClass.h with the following line:
- (void)otherMethodWithBlock:(void(^)(void))callbackBlock;
The calling code will need to reside in an Objective-C++ compilation unit (caller.mm):
void callOtherMemberWithCPP(MyCPPClass* cpp_obj, MyClass* objc_obj)
{
[objc_obj otherMethodWithBlock:^{
cpp_obj->memberFunction();
}];
}
Note that this does not deal with object lifetimes. If you're managing lifetimes on the C++ side with std::shared_ptr, you can use that in your Objective-C++ code too, in which case we might end up with something like:
void callOtherMemberWithCPP(std::shared_ptr<MyCPPClass> cpp_obj, MyClass* objc_obj)
{
[objc_obj otherMethodWithBlock:^{
cpp_obj->memberFunction();
}];
}
In this case, the C++ object will only have its reference count decremented when the Objective-C class is done with the block.
For completeness, the other way to do this would be to use C function pointer syntax. In this case, you would need to declare the Objective-C method along these lines:
- (void)otherMethodWithCallback:(void(*)(void*))callback object:(void*)opaqueCallbackArgument;
And the C++ class's method call would need to be wrapped in a free function or static member function:
void memberFunctionCallback(void* opaque_object)
{
MyCPPClass* object = static_cast<MyCPPClass*>(opaque_object);
object->memberFunction
}
…and then call the Objective-C method like this:
[objc_obj otherMethodWithCallback:memberFunctionCallback object:cpp_obj];
Making this version work nicely with automatic lifetime mechanisms such as shared_ptr is a lot more tricky though.

Qt/C++ Override function without subclassing

I would like to override a virtual function of a QWidget without subclassing it. It is possible in java. I found this link:
overriding methods without subclassing in Java
Not sure if there is a way in c++ too. Any ideas?
You can't override without inheritance. The code in the linked example does subclass. Perhaps the confusion comes from the fact that it doesn't use the extends keyword. It creates an anonymous subclass of XStream and overrides it's method. Such classes exist in C++ as well and similar code is possible. The naming convention is a bit different. Classes that have no name, but do have a named instance are called unnamed †. Here is my transliteration of the code to show how the example can be done with unnamed class in C++:
class SomeClass {
public:
void myMethod() {
class: public XStream {
protected:
MapperWrapper wrapMapper(const MapperWrapper& next) override {
return MapperWrapper(next); // the example is cut off here, persumably it's creating another nested anonymous class, but i'll keep this simple
}
} xstream;
}
};
You can replace the XStream with QWidget and wrapMapper with one of it's virtual classes if you want to override it in this way.
Anonymous classes are often used for callbacks in Java. But in C++ we have function pointers and lately lambdas, which is probably why the use of unnamed classes is much rarer in C++ code compared to Java. Also, before c++11 unnamed classes were not allowed as template parameters, so they would have been a poor choice for a callback functor.
† In c++, an Anonymous class (or struct) would be one that has no named instance either. It could be a member of another, outer class and the members of the anonymous class would be brought to the namespace of the parent class. Except, anonymous classes are not allowed by the standard. How can there be a definition for such thing then? Well, anonymous unions are allowed and anonymous classes are analoguous to them. Anonymous structs are allowed by C11 standard, though.
Your Java example is a subclass -- it's just an anonymous subclass. The #Override keyword is simply a diagnostic aid: it issues an error if the method doesn't override a superclass. Removing #Override has no effect on the generated code. C++11 has it too -- see this link.
In C++ as in Java, you can't override a virtual function without declaring a subclass. If you want to use Qt effectively, you will have to get used to it!

C++ functions in Objective C

I am getting a bit confused how to call C++ functions in Objective C.
I've declared my functions as:
void InitializeSearchRegistration();
In the header file in between the interface and end. I've then defined it in my mm file as:
void InitializeServiceRegistration()
{
}
What I am struggling with is how to define it as public to ensure other classes can see it. I've tried public but get an error. Usually C++ methods have to be declared in a class block.
Any advice would be great.
You can't add C++ member functions to an Objective-C class using Objective-C++. You should consider redesigning your class to either have a totally C++ interface (in which case it should be a C++ class or struct) or a totally Objective-C interface (in which case it should define ObjC class and instance methods, not C++ member functions).
There are two ways to go about this, the first is to combine C++ and Objective C into another language, called Objective C++. The other is to communicate over plain C functions.

Calling an Objective-C class method from C++

I am having some trouble calling an objective-c class method from a C++ file. Example:
In my .h:
#interface MyClass : NSObject {
}
+ (void)myMethod:(NSString *)str;
In my .m:
+ (void) myMethod:(NSString *)str { ... }
In my .cpp:
??
How can you call myMethod since there is no class instance? Its essentially a static?
Thanks
Objects in C++ are incompatible with objects in Objective-C. You cannot simply call an Objective-C method from C++.
There are some solutions, however:
Use Objective-C++. Rename your .cpp to .mm, then you can use Objective-C syntax in your C++ code: [FlurryAnalytics myMethod: #"foo"];
Use direct calls to the Objective-C runtime system. I won't tell you how to, because I really think you shouldn't, and in fact that you don't want to.
Write a plain-C interface. That is, in some .m file, define void myFunction(const char *str) { ... } and call that from C++. You can find an example of this here.
You're going to need a .mm to call an Objective-C method, rather than a .cpp. Beyond that your comment that 'it's essentially static' is accurate in the sense that you would call it with similar logic to the way you would call static class functions in C++:
[MyClass myMethod:#"Some String"];
Though the method isn't static in the C++ sense for a bunch of reasons that don't affect this answer — it isn't resolved at compile time and it does operate within a class (the MyClass metaclass).