【问题标题】:Linker error calling .mm function from .cpp file从 .cpp 文件调用 .mm 函数的链接器错误
【发布时间】:2013-09-25 14:13:43
【问题描述】:

我在我当前的 Xcode 4.6 项目中添加了一个 obj-c 类(.mm 和 2 个标头)。一个头文件具有调用 obj-c 类的原型,另一个定义 .mm 类。这是它的样子。

myinterface.h

#ifndef MYINTERFACE_H
#define MYINTERFACE_H

BOOL LaunchApp(CAtlString exePath);

#endif

myLaunchClass.h

#import "myinterface.h"

@interface myLaunchClass : NSObject
-(BOOL) LaunchApp:(CAtlString)exePath;
@end

myLaunchClass.mm

@import "myLaunchClass.h"

@implementation myLaunchClass
-(BOOL) LaunchApp:(CAtlString)exePath
{
    ....
    return someCondition;
}
@end

从那里编译好。我在 Build Phases 中将 .mm 文件添加到 Target 中,并将 header 位置添加到 Build Settings 中的 Header Search Paths 中。

当我在 .cpp 文件 (#include "myinterface.h") 中包含头文件时,我没有任何错误。但是,当我调用我的函数 (::LaunchApp(exePath);) 时,出现链接器错误。

错误

Undefined symbols for architecture i386:
  "LaunchApp(CAtlString)", referenced from:
      myCppFile::myCppFunction() const in myCppFile.o
ld: symbol(s) not found for architecture i386

有什么想法吗?我认为这对于 Mac 开发人员来说一定是一个明显的错误,但我对 Mac 编程还是有点陌生​​。任何帮助表示赞赏。

【问题讨论】:

    标签: c++ objective-c linker osx-lion xcode4.6


    【解决方案1】:

    Objective-C++ 不以这种方式互操作。 -(BOOL)LaunchApp:(CAtlString)exePath 在 Objective-C 类上声明一个实例方法。该方法只能从 Objective-C(即 .m、.mm)文件中调用,并且如果方法签名包含 C++ 类型(就像这里所做的那样),那么它只能从 Objective-C++ (.mm) 中调用文件。此外,-(BOOL)LaunchApp:(CAtlString)exePath 是一个实例方法,您似乎在调用它,就好像它是一个 C++ 静态/类方法一样,这也不起作用。

    如果您想包装自己的 Objective-C 类以使其可供直接 C++ 消费者使用,则必须执行以下操作:

    MyLaunchClass.h

    #if __cplusplus
    #import <string>
    #endif
    
    @interface MyLaunchClass : NSObject
    
    #if __cplusplus
    - (BOOL)launchApp: (std::string)str;
    #endif
    
    @end
    
    #if __cplusplus
    
    struct WrappedMyLaunchClass
    {
        MyLaunchClass* mImpl;
    
        WrappedMyLaunchClass() : mImpl([[MyLaunchClass alloc] init]) { };
    
        ~WrappedMyLaunchClass() { mImpl = nil; }; // Assuming ARC here. for non-ARC, [mImpl release]
    
        bool LaunchApp(std::string str)
        {
            return !![mImpl launchApp:str];
        }
    };
    
    #endif
    

    MyLaunchClass.mm

    #import "MyLaunchClass.h"
    #import <string>
    
    @implementation MyLaunchClass
    
    - (BOOL)launchApp: (std::string)str
    {
        NSLog(@"%s", str.c_str());
        return YES;
    }
    
    @end
    

    SomeOtherFile.cpp

    void someOtherFunction()
    {
        WrappedMyLaunchClass x;
        x.LaunchApp("foobar");
    }
    

    总之,您高估了 C++ 和 Objective-C++ 的互操作性。您可以将 Objective-C++ 视为“Objective-C 增加了具有 C++ 类型变量的能力和调用 C++ 代码的能力”,但 不是 是“声明 C++ 类型的替代语法。”

    Caveat Emptor!:这大大简化了将 Objective-C 对象有意义地包装在 C++ 对象中所涉及的内容。 C++ 的按值/按引用语义与 Objective-C 大不相同,如果 C++ 对象曾经按值传递(即通过复制构造函数)等。我提供的示例只是为了说明为什么您尝试的操作不起作用,而不是作为将 Objective-C 对象包装在 C++ 对象中的某种通用代码。

    【讨论】:

    • 我需要 .mm 文件中的 someOtherFunction 吗?如果我将 .mm 类更改为更像 c++(即:MyLaunchClass 类而不是 @interface MyLaunchClass)会有什么区别?
    • someOtherFunction 可以在 .cpp 文件中。它不直接与 Objective-C++ 交互,只是直接与 C++ 的东西交互。任何涉及 Objective-C++ 的东西都必须在 .mm 文件中。 class MyLaunchClass@interface MyLaunchClass 有什么区别? class MyLaunchClass 将是一个 C++ 类,无法传递给传统的 Objective-C API。这么说可能最简单:您可以直接从 Objective-C++ 调用直接 C++。您不能直接从直接 C++ 调用 Objective-C++。
    猜你喜欢
    • 1970-01-01
    • 2011-05-12
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 2017-09-12
    相关资源
    最近更新 更多