簡體   English   中英

從 Objective-C 調用 C++

[英]Calling C++ from Objective-C

對於那些已經成功地能夠從 Objective-C 調用 C++ 代碼的人,你能指教我嗎?

這個鏈接說你需要使用他在他的文章中描述的技術來包裝你的 C++ 代碼。 看起來不錯,但我仍然有問題。

鏈接表示,只要調用 C++ 類的 Objective-C 類已轉換為 .mm(Objective-C++)類,那么兩者應該可以很好地協同工作。

當我嘗試添加方法調用時,這些方法中的每一種都讓我感到悲傷。 有人可以給我一個簡單的Hello World iOS應用程序的代碼,它使用Objective-C作為“Hello”部分,使用C++類作為“World”部分,中間有一個Objective-C++類? 或者我仍然有整個概念錯誤?

本質上,您需要一個擴展名為 .mm 的 ObjC 類,它調用帶有 .mm 擴展名的 ObjC 類。 第二個將用作 C++ 包裝器類。 包裝類將調用您實際的 .cpp 類。 這有點棘手,所以我會給你一些詳細的代碼。 以下是該項目的概述:

在此處輸入圖片說明

在您的 ObjC 代碼(ViewController)中,您將調用 CplusplusMMClass

- (IBAction)buttonPushed:(UIButton *)sender {
    self.mmclass = [[CplusplusMMClass alloc]init];  // bad practice; but showing code
    NSString *str = [self.mmclass fetchStringFromCplusplus];
    [self populateLabel:str];
}

這是 CplusplusMMClass .h 和 .mm

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

@interface CplusplusMMClass : NSObject
@end

@interface CplusplusMMClass()
@property (nonatomic, strong) WrapperClass *wrapper;
- (NSString*)fetchStringFromCplusplus;
@end

#import "CplusplusMMClass.h"
#import "WrapperClass.h"

@implementation CplusplusMMClass

- (NSString*)fetchStringFromCplusplus {
    self.wrapper = [[WrapperClass alloc] init];
    NSString * result = [self.wrapper getHelloString];
    return result;
}

@end

這是 WrapperClass .h 和 .mm

#ifndef HEADERFILE_H
#define HEADERFILE_H

#import <Foundation/Foundation.h>

#if __cplusplus

#include "PureCplusplusClass.h"

@interface WrapperClass : NSObject
@end

@interface WrapperClass ()
- (NSString *)getHelloString;
@end


#endif
#endif

#import "WrapperClass.h"

#include "WrapperClass.h"
#include "PureCplusplusClass.h"

using namespace test;

@interface WrapperClass ()
@property (nonatomic) HelloTest helloTest;
@end

@implementation WrapperClass

- (NSString *)getHelloString {
    self.helloTest = *(new HelloTest);
    std::string str = self.helloTest.getHelloString();
    NSString* result = [[NSString alloc] initWithUTF8String:str.c_str()];
    return result;
}

@end

這是 PureCplusplusClass .h 和 .cpp

#ifndef __HelloWorld__PureCplusplusClass__
#define __HelloWorld__PureCplusplusClass__

#include <stdio.h>
#include <string>

using namespace std;

namespace test {
    class HelloTest
    {
    public:
        std::string getHelloString();
    };
}

#endif /* defined(__HelloWorld__PureCplusplusClass__) */

#include <stdio.h>
#include <string>

std::string test::HelloTest::getHelloString() {
    std::string outString = "Hello World";
    return outString;
}

這段代碼並不完美! 我在識別名稱空間測試時遇到問題。 我會在可以的時候更新。

但這應該會讓你到達那里!!!!

根據要求; 一個例子:

#import <Foundation/Foundation.h>
#import <vector>
#import <string>

int main(int argc, const char **argv) {
    std::vector<std::string> v;
    v.push_back("Hello");
    v.push_back("World");
    for (std::string s : v)
        NSLog(@"%s", s.c_str());
    return 0;
}

$ clang -std=c++11 -stdlib=libc++ -o callcpp callcpp.mm -framework Foundation -lc++
$ ./callcpp
2013-10-07 17:16:13.725 callcpp[37710:707] Hello
2013-10-07 17:16:13.726 callcpp[37710:707] World

另一個(人為的):

使用 C++ 類作為 ivar:

文件 Foo.h

#import <Foundation/Foundation.h> 

@interface Foo : NSObject
@property (nonatomic, readonly) NSString* what;
@end

文件:Foo.mm

#import "Foo.h"
#include <string>

@implementation Foo {
    std::string _string;  // C++ class must have a default c-tor
}

- (id)init
{
    self = [super init];
    if (self) {
        _string = "Hello, World!"
    }
    return self;
}

- (NSString*) what {
    NSString* result = [[NSString alloc] initWithBytes:_string.data()
                                                length:_string.size() 
                                              encoding:NSUTF8StringEncoding];
    return result;
}

@end

注意:

可執行文件可能需要顯式鏈接 C++ 庫,例如通過向“其他鏈接器標志”添加附加標志: -lc++

或者,可以將main.m文件重命名為main.mm

后者在選擇“正確”庫時更加穩健,因為工具鏈會自行完成。 但也許,對於其他檢查項目的人來說,重命名的“main.m”可能不是那么明顯,可能會引起混淆。

我在 xcode 12.4 中遇到了這種情況,需要在 Objective-c 項目中使用現有的 C++ 類“CppModule”。 這是我所做的。

  1. 第一個問題是 CppModule.hpp 中的 #include 給出了一個編譯器錯誤:'string' 文件未找到。 通過將 .hpp 文件內容包裝在
#if defined __cplusplus declarations #endif
  1. 然后字符串 var 聲明給出了另一個編譯器錯誤:Unknown type name 'string'; 你的意思是'std::string'嗎? 通過以下方式修復:
 #include <string> using namespace std;
  1. C++ CppModule.cpp、CppModule.hpp 包含文件、調用objective-c module.m 和它的module.h 文件都必須使用xcode 的Inspector(在編輯器的右上角)設置為“Objective-C++ Source”類型窗)。 將 module.m 重命名為 module.mm 還將類型設置為“Objective-C++ Source”(xcode 12.4)。 使用 .mm 可能很好,提醒一下它調用 C++。

在 module.h 文件中包含 C++ 頭文件:

 #include < CppModule.hpp>
  1. 奇怪的是(對我來說)在 module.h 文件中“CppModule”未被識別為已知類型,因此您不能在 module.h 中聲明該類型的變量或屬性,但在 module.m(m) 文件中它是一種已知類型。 在 module.mm 文件中,@implementation 后添加:
 static CppModule *module_cpp;
  1. 現在您可以,例如在 module.mm 的 init 中,調用 C++ 模塊的初始化程序,例如:
 module_cpp = new CppModule(parameters);

並且 C++ 模塊仍然可以通過該靜態 module_cpp * 指針訪問。

  1. 在您的objective-c 方法中調用module.cpp 的方法(示例):
 CppModule::Result r = module_cpp->CppMethod();

似乎工作得很好!

如果有人能解釋 4 中的奇怪之處,我將不勝感激。

我需要的模塊只是做一些復雜的(數字)計算,我不想將代碼轉換為 Objective-C。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM