在C++中将目标 C "code blocks"转换为等效值

Convert Objective C "code blocks" to equivalent in C++

本文关键字:转换 blocks code 目标 C++      更新时间:2023-10-16

我需要一个帮助转换一些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){//一些代码…

            });

最直接的类比是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];
});

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

你可以使用c++ lambdas而不改变被调用的函数,因为lambdas可分配给块(但不能反过来)。

只要对块的需求是您的,而不是系统的。

就像我说的,有几种方法。函数指针需要最少的样板文件,但它们需要一个额外的参数来传递来自调用者的上下文(在您的例子中是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));