简体   繁体   中英

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

Right now my OS X 10.9 project is set up with a GUI in Objective-C and all the processing in a C++ class. This doesn't seem like the best way, but this was given to me and I have to work with these constraints. I currently have a NSSlider in the Cocoa GUI. I want to be able to have this NSSlider control a variable x in the C++ class.

Currently the tolerance bar is working when I run the program (working meaning it's continuously updating its value as per my sliding).

Header for NSSlider ( Slider.h ):

@interface Slider : NSObject {
@private
    __weak IBOutlet NSTextField *sliderValue;
    __weak IBOutlet NSSlider *slider;
}

- (IBAction)updateSliderValue:(id)sender;

@end

Implementation for the NSSlider ( Slider.mm ):

#import "Slider.h"      // The NSSlider object
#import "CMain.h"       // The C++ class that does all the processing (not sure if this is the way to include a C++ interface in an Objective-C++ class or if this will allow me to call its methods)

@implementation Slider

-(void) awakeFromNib {
    [slider setIntValue:40];
    [sliderValue setIntValue:[slider intValue]];
}

- (IBAction)updateSliderValue:(id)sender {
    [sliderValue setIntValue:[slider intValue]];
    // Here is where I'd think that if I have a setValueofX(int number) method in the C++ class
    // I could call this somehow using objective-C++. I don't know if I can or how to call this method here
}

Here is the relevant snippet from Main.h :

class CMain(){
    public:
        CMain();
        void setValueofX(int number);
        int getValueofX();

    private:
        int x;
};

How do I include CMain.h in the Objective-C++ (which, the .h file or .mm file? and how?) such that it would allow me to call the methods in CMain.h ? How would I phrase the method call in Objective-C to set x 's value using the setValueofX(sliderValue) ?

Please let me know if more information is needed! Any help or thoughts are appreciated!

Thanks!

The code for calling the setter is the same as it would be in C++. However, you'd need a pointer to the CMain object to be able to call the method on it. I don't know where that object currently resides. If there is no object yet in another object, you probably want to create one, which you can by just declaring an instance variable CMain myCMain; and then calling myCMain.setValueOfX( [slider intValue] ); in updateSliderValue: .

As to where to include the C++ class, it's really your choice. However, if you use any C++ in your header, it will take a bunch of careful extra work to include it from plain .m files. So in general I try to stick to plain C and ObjC in the header, and only use C++ in the .mm file. You can use a class extension (sometimes called "class continuation" as well) to declare additional ivars in your .mm file to keep them out of the header.

If you want more info about ObjC++, I answered in detail on another post: Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link? and that also links to a Podcast I was a guest on where I talk about a lot of the details and tricks for integrating ObjC and C++.

Aside: I hope these are not actual names and comments you're using. Never have an ObjC class without a prefix (3 letters, Apple stated they reserve all 2-letter prefixes for their own use, and they've used un-prefixed internal class names in the past which broke some peoples' programs). Also, "Slider" is a bad name, as NSSlider is the actual slider, and this sounds like it should be a subclass. You really want to call this an ISTSliderController or whatever.

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

Here's an all objective-c and objective-c++ answer:

CMain.h:

#ifndef Testing_CMain_h
#define Testing_CMain_h

@interface CCMain : NSObject
-(CCMain*) init;
-(void) dealloc;

-(void)setValueofX:(int)number;
-(int)getValueofX;
@end

#endif

CMain.mm:

#import <Foundation/Foundation.h>
#import "CMain.h"

class CMain {
private:
    int x;

public:
    CMain() : x(0) {}

    void setValueofX(int number) {x = number;}
    int getValueofX() const {return x;}
};


@interface CCMain ()
@property (nonatomic, assign) CMain* inst;
@end

@implementation CCMain

-(CCMain*) init
{
    if (!_inst)
    {
        _inst = new CMain();
    }
    return self;
}

-(void) dealloc
{
    delete _inst;
    _inst = nil;
}

-(void)setValueofX:(int)number
{
    _inst->setValueofX(number);
}

-(int)getValueofX
{
    return _inst->getValueofX();
}

@end

and if you want to use C-style functions then:

setValueofX(cmain_instance, value);
int val = getValueofX(cmain_instance);

And this works because a C++ class function in C is the same as:

void CMain::MyFunc(int X);
//vs..
void MyFunc(CMain* inst, int X);

Both are the exact same thing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM