将 Objective C“代码块”转换为 C++ 中的等价物

Posted

技术标签:

【中文标题】将 Objective C“代码块”转换为 C++ 中的等价物【英文标题】:Convert Objective C "code blocks" to equivalent in C++ 【发布时间】:2013-01-03 22:03:43 【问题描述】:

在将一些 Objective C“代码块”方法转换为 C++ 中的等效方法时,我需要帮助。 请指教。

A 被用作代码块...

.h 文件中定义..

typedef void (^A)(void*); //argument is ptr to B

在一个.mm文件中使用..

[[hello getInstance] getB]->queueLoadImageWithBlock([self.str UTF8String], (A

)^(void* img) //一些代码...

            );

【问题讨论】:

C++ 世界呈现出什么样的界面?在 C++ 中,有三种不同的结构实现了“固定函数”的概念——有指向成员的指针、函子和 C 风格的函数指针。相关的 Cocos2dx API 期待哪一个? 它应该是 c++ 风格的函数指针或接近上面给定代码 sn-p 的东西。 queueLoadImageWithBlock() 是系统提供的吗?如果是这样,它的第二个参数的类型是什么?如果它是一个块,那么你无法用函数指针来满足它。它们只是不等价的。 yes..第二个参数是 blcok..并且 queueLoadImageWithBlock() 不是系统提供的,而是手动编写的。如果 queueLoadImageWithBlock() 的定义需要更改,我可以。但请告诉我如何在 c++ 中实现相同的功能。 【参考方案1】:

最直接的比喻是std::function。这是一个具有签名的值类型(例如std::function<int(int)>,并且可以是适当签名的任何函数对象。可以在调用站点使用 lambda 代替块。

obj->queueLoadImageWithBlock(self.url, [](void* img)

    UIImage* img2 = (UIImage*)img;
    UIImageView* iv = [[UIImageView alloc] initWithImage:img2];
    iv.backgroundColor = [UIColor clearColor];
    [self.iconSlot addSubview:iv];
    iconLoaded(iv);
    [iv release];
);

【讨论】:

它说“命名空间 std 中没有名为“函数”的类型”。我需要包含任何头文件吗? 您可能应该使用此代码适用的 Xcode 版本来限定该答案。【参考方案2】:

使用 Apple 的 clang 版本,您可以使用 C 和 C++ 以及 Objective-C 中的块。这显然是非标准 C++,但它可以工作。

您可以在不更改被调用函数的情况下使用 C++ lambda,因为 lambda 可以分配给块(但不能反过来)。请参阅this question 了解更多信息。

【讨论】:

【参考方案3】:

只要块的要求是你的而不是系统的。

就像我说的,有几种方法。函数指针需要最少的样板文件,但它们需要一个额外的参数来从调用者传递上下文(在你的情况下是 self 东西)。函子和指向成员的指针通常需要模板机制才能工作,我们不要去那里。所以有了一个函数指针,它会是这样的:

//Let's define a callback datatype
typedef void (*ResourceLoadObjFuncPtr)(void *, void*);
//argument 1 is ptr to ResourceLoadDescriptor, argument 2 is iconSlot, whatever it is

//Function that implements that type:
void MyLoad(void *img, void *iconSlot)

    UIImage* img2 = (UIImage*)img;
    UIImageView* iv = [[UIImageView alloc] initWithImage:img2];
    iv.backgroundColor = [UIColor clearColor];
    [(TheTypeOfIconslot*)iconSlot addSubview:iv];
    iconLoaded(iv);
    [iv release];

您必须修改queueLoadImageWithBlock 的原型以接受ResourceLoadObjFuncPtr 参数而不是ResourceLoadObjCBlockCB,以及上下文的另一个参数(在我们的例子中只是iconSlot)。

然后调用:

[[GameViewController getInstance] getResourceLoadMediator]->
    queueLoadImageWithFunction([self.url UTF8String], MyLoad, self.iconSlot);

块是闭包——它们捕获声明它们的函数的变量。 C++ 不提供 ios 上的 GCC 支持的闭包(除了块)。因此,您必须手动将变量从函数范围传递给函数参数。在我们的例子中,如果我的假设是正确的,那么只有一个变量;在更复杂的情况下,您必须将它们包装在一个结构中并传递一个指向其中的指针。

另一种方法是使用抽象基类和通过其构造函数捕获上下文的具体实现。这将是这样的:

//Callback type
class ResourceLoader

public:
    virtual void Load(void *) = 0;
;

//A callback implementation - not a function, but a class

class MyResourceLoader : public ResourceLoader

    IconSlotType *iconSlot;

    void Load(void *img)
    
        //Same loader stuff as above
    
public:
    MyResourceLoader(IconSlotType *isl)
    :iconSlot(isl)
    
 ;

queueLoadImageWithBlock 等效项现在将采用 ResourceLoader* 类型的第二个参数,并且没有第三个参数。至于调用,存在回调对象生命周期的问题。 queueLoadImageWithBlock 是异步的——也就是说,它在调用回调之前是否返回?如果是这样,那么 MyResourceLoader 的本地实例将不会这样做,您必须动态创建一个并以某种方式处置它。假设它是同步的(即返回后不调用回调):

MyResourceLoader ResLoader(self.iconSlot);
[[GameViewController getInstance] getResourceLoadMediator]->
    queueLoadImageWithLoader([self.url UTF8String], &ResLoader);

如果不是:

[[GameViewController getInstance] getResourceLoadMediator]->
    queueLoadImageWithLoader([self.url UTF8String], new MyResourceLoader(self.iconSlot));

【讨论】:

-1:确实没有理由推荐函数指针而不是函子。如果编写模板的想法让您感到害怕,请尝试std::functionboost::function,它们开箱即用。或者,地狱,lambdas。 不太对。虽然 gcc 不支持 c++11 lambda,但 clang(您应该使用任何一种方式)确实支持许多 c++11 功能,而 lambda 函数就是其中之一。 你抽什么烟? GCC 有 lambda。该死,甚至 Visual Studio 也有 lambda。 非常适合详细解释所有可能的解决方案。对于给定的问题,这对我没有帮助,而是清除了我的几个疑问。你这个摇滚伙伴:-)

以上是关于将 Objective C“代码块”转换为 C++ 中的等价物的主要内容,如果未能解决你的问题,请参考以下文章

将字符串从 C++ 转换为 Swift

将 NSStrings 转换为 C 字符并从 Objective-C 调用 C 函数

将方法从 Objective C 转换为 Swift

Objective C 将 int 转换为 NSString (iPhone)

从 Objective C 将回调/闭包转换为 Swift

将字符串转换为int-objective c [重复]