- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我发现分配 block 对于 Objective-C 类参数和 C++ 类参数的行为有所不同。
假设我有这个简单的 Objective-C 类层次结构:
@interface Fruit : NSObject
@end
@interface Apple : Fruit
@end
然后我可以写这样的东西:
Fruit *(^getFruit)();
Apple *(^getApple)();
getFruit = getApple;
这意味着,相对于 Objective-C 类, block 其返回类型是协变的:返回更具体内容的 block 可以被视为“返回更通用内容的 block 的“子类”。在这里,可以将提供苹果的 getApple
block 安全地分配给 getFruit
block 。事实上,如果稍后使用,当您期待 Fruit *
时,总是可以保存以接收 Apple *
。而且,从逻辑上讲,相反的情况是行不通的:getApple = getFruit;
无法编译,因为当我们真正想要一个苹果时,我们并不高兴只得到一个水果。
同样,我可以这样写:
void (^eatFruit)(Fruit *);
void (^eatApple)(Apple *);
eatApple = eatFruit;
这表明 block 在其参数类型上是协变的:可以在需要处理更具体参数的 block 的地方使用可以处理更通用参数的 block 。如果一个方 block 知道如何吃水果,它也会知道如何吃苹果。同样,反之亦然,这将无法编译:eatFruit = eatApple;
。
这一切都很好——在 Objective-C 中。现在让我们在 C++ 或 Objective-C++ 中尝试一下,假设我们有这些类似的 C++ 类:
class FruitCpp {};
class AppleCpp : public FruitCpp {};
class OrangeCpp : public FruitCpp {};
遗憾的是,这些 block 分配不再编译:
FruitCpp *(^getFruitCpp)();
AppleCpp *(^getAppleCpp)();
getFruitCpp = getAppleCpp; // error!
void (^eatFruitCpp)(FruitCpp *);
void (^eatAppleCpp)(AppleCpp *);
eatAppleCpp = eatFruitCpp; // error!
Clang 提示“从不兼容的类型分配”错误。因此,相对于 C++ 类, block 的返回类型和参数类型似乎不变。
这是为什么呢?我对 Objective-C 类所做的同样的论证不也适用于 C++ 类吗?我错过了什么?
最佳答案
由于 Objective-C 和 C++ 对象模型之间的差异,这种区别是有意为之的。特别是,给定一个指向 Objective-C 对象的指针,可以将该指针转换/转换为指向基类或派生类,而无需实际更改指针的值:无论如何,对象的地址都是相同的。
因为 C++ 允许多重继承和虚拟继承,所以 C++ 对象的情况并非如此:如果我有一个指向 C++ 类的指针,并且我将该指针强制转换/转换为指向基类或派生类,我可能会来调整指针的值。例如,考虑:
class A { int x; }
class B { int y; }
class C : public A, public B { }
B *getC() {
C *c = new C;
return c;
}
假设 getC() 中的新 C 对象在地址 0x10 处分配。指针“c”的值为0x10。在 return 语句中,指向 C 的指针需要调整为指向 C 中的 B 子对象。因为 B 在 C 的继承列表中位于 A 之后,所以它(通常)会在 A 之后布置在内存中,因此这意味着添加一个4 个字节的偏移量(== sizeof(A)) 到指针,因此返回的指针将为 0x14。类似地,将 B* 转换为 C* 将从指针中减去 4 个字节,以考虑 B 在 C 中的偏移量。在处理虚拟基类时,想法是相同的,但偏移量不再是已知的,编译时常量:在执行期间通过 vtable 访问它们。
现在,考虑一下这对作业的影响,例如:
C (^getC)();
B (^getB)();
getB = getC;
getC block 返回指向 C 的指针。要将其转换为返回指向 B 的指针的 block ,我们需要通过添加 4 个字节来调整每次调用该 block 返回的指针。这不是对 block 的调整;而是对 block 的调整。这是对 block 返回的指针值的调整。人们可以通过合成一个包装前一个 block 并执行调整的新 block 来实现这一点,例如,
getB = ^B() { return getC() }
这可以在编译器中实现,当使用需要调整的协变返回类型的函数覆盖虚拟函数时,编译器已经引入了类似的“thunk”。然而,使用 block 会导致一个额外的问题: block 允许与 == 进行相等比较,因此要评估是否“getB == getC”,我们必须能够查看由赋值“getB =”生成的 thunk getC”来比较底层 block 指针。同样,这是可以实现的,但需要更重量级的 block 运行时,能够创建(唯一的)thunk,能够对返回值(以及任何逆变参数)执行这些调整。虽然所有这些在技术上都是可行的,但成本(运行时大小、复杂性和执行时间)超过了 yield 。
回到 Objective-C,单继承对象模型永远不需要对对象指针进行任何调整:只有一个地址指向给定的 Objective-C 对象,无论指针的静态类型如何,因此协变/逆变从不需要任何重击, block 分配是一个简单的指针分配(+ ARC 下的 _Block_copy/_Block_release)。
关于pointers - 分配 block 指针: differences between Objective-C vs C++ classes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15312774/
我遵循了一本名为“Sitepoint Full Stack Javascript with MEAN”的书中的教程,我刚刚完成了第 6 章,应该已经创建了一个带有“数据库”的“服务器”。数据库只不过是
在 Jquery 中,我创建两个数组,一个嵌入另一个数组,就像这样...... arrayOne = [{name:'a',value:1}, {name:'b',value:2}] var arra
这个问题在这里已经有了答案: What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wa
我被放在别人的代码上,有一个类用作其他组件的基础。当我尝试 ng serve --aot(或 build --prod)时,我得到以下信息。 @Component({ ...,
我正在测试一些代码,并使用数据创建了一个 json 文件。 问题是我在警报中收到“[object Object],[object Object]”。没有数据。 我做错了什么? 这是代码:
我想打印 [object Object],[object Object] 以明智地 "[[{ 'x': '1', 'y': '0' }, { 'x': '2', 'y': '1' }]]"; 在 ja
我有一个功能 View ,我正在尝试以特殊格式的方式输出。但我无法让列表功能正常工作。 我得到的唯一返回是[object Object][object Object] [object Object]
在使用优秀的 Sim.js 和 Three.js 库处理 WebGL 项目时,我偶然发现了下一个问题: 一路走来,它使用了 THREE.Ray 的下一个构造函数: var ray = new THRE
我正在使用 Material UI 进行多重选择。这是我的代码。 {listStates.map(col => (
我的代码使用ajax: $("#keyword").keyup(function() { var keyword = $("#keyword").val(); if (keyword.
我遇到了下一个错误,无法理解如何解决它。 Can't resolve all parameters for AuthenticationService: ([object Object], ?, [o
我正在尝试创建一个显示动态复选框的表单,至少应选中其中一个才能继续。我还需要获取一组选中的复选框。 这是组件的代码: import { Component, OnInit } from '@angul
我正在开发 NodeJs 应用程序,它是博客应用程序。我使用了快速验证器,我尝试在 UI 端使用快速闪存消息将帖子保存在数据库中之前使用闪存消息验证数据,我成功地将数据保存在数据库中,但在提交表单后消
我知道有些人问了同样的问题并得到了解答。我已经查看了所有这些,但仍然无法解决我的问题。我有一个 jquery snipet,它将值发送到处理程序,处理程序处理来自 JS 的值并将数据作为 JSON 数
我继承了一个非常草率的项目,我的任务是解释为什么它不好。我注意到他们在整个代码中都进行了这样的比较 (IQueryable).FirstOrDefault(x => x.Facility == fac
我只是在删除数组中的对象时偶然发现了这一点。 代码如下: friends = []; friends.push( { a: 'Nexus', b: 'Muffi
这两个代码片段有什么区别: object = nil; [object release] 对比 [object release]; object = nil; 哪个是最佳实践? 最佳答案 object
我应该为其他人将从中继承的第一个父对象传递哪个参数,哪个参数更有效 Object.create(Object.prototype) Object.create(Object) Object.creat
我在不同的对象上安排不同的选择器 [self performSelector:@selector(doSmth) withObject:objectA afterDelay:1]; [self per
NSLog(@"%p", &object); 和 NSLog(@"%p", object); 有什么区别? 两者似乎都打印出一个内存地址,但我不确定哪个是对象的实际内存地址。 最佳答案 这就是我喜欢的
我是一名优秀的程序员,十分优秀!