8

最近为 iPhone 做了一些开发,我开始注意到一个有趣的设计模式,在 iPhone SDK 中使用了很多,关于对象可变性。

似乎典型的方法是定义一个不可变的类NSFoo,然后从中派生一个可变的后代NSMutableFoo。通常,NSFoo该类定义了数据成员、getter 和只读操作,派生的NSMutableFoo添加了 setter 和 mutating 操作。

由于对 C++ 更加熟悉,我不禁注意到这似乎与我在 C++ 中编写相同代码时所做的完全相反。虽然您当然可以采用这种方法,但在我看来,更简洁的方法是创建一个Foo类,将 getter 和只读操作标记为const函数,并在同一个类中实现可变操作和 setter。然后你会得到一个可变类,但是 typesFoo const*Foo const&都是不可变的等价物。

我想我的问题是,我对这种情况的看法有意义吗?我理解为什么 Objective-C 会做不同的事情,但是我错过了 C++ 中的二分类方法有什么优势吗?还是我完全错过了重点?

不是一个过于严肃的问题——更多的是出于我自己的好奇心。

4

2 回答 2

4

Objective-C 太动态了。在 C++ 中,const 限定在编译时强制执行,并且在运行时任何违反 const 限定的行为(例如通过非 const 限定指针修改 const 限定对象)都是未定义的行为。

这与 Objective-C 中没有私有方法的原因部分相同。您可以自由地向任何对象发送您想要的任何消息。运行时调度接受一个对象和一个消息,并解析一个方法实现来调用。

如果const合格的对象只能调用const合格的方法,它将完全破坏 Objective-C 和 Foundation 的动态特性,因为需要在运行时进行这样的检查(首先检查将确定发送的消息是否解析为 const 限定的实现对于该特定实例,并进行另一次检查以确定实例本身是否是 const 限定的)。考虑这个理论例子:

NSArray *mutableArray = [[NSArray alloc] init];

NSString *mutableString = @"I am a mutable string";
const NSString *immutableString = @"I am immutable because I am const-qual'd";

[mutableArray addObject:mutableString];
[mutableArray addObject:immutableString]; // what happens?!

// and what happens here (both immutable and mutable strings would respond
// to the same selectors because they are the same class):
[mutableArray makeObjectsPerformSelector:@selector(aMutableOperation)];

突然间你失去了动力。就像现在一样,可变和不可变对象可以放在一个不可变或可变集合中。

拥有一个可变的子类保持了 Objective-C 的动态特性,并使运行时保持简单。前段时间有一个关于私有方法的类似话题。

于 2010-06-10T00:53:01.300 回答
0

想法...

Mac,如您所知,在 C++ 中,您可以将“A”和“const A”视为两种不同的类型,它们的唯一关系是

  1. "A" 和 "A &" 可以隐式转换为 "const A" 和 "const A &" 等等...
  2. "const A &" 可以 const_cast 为 "A &" 等等...

编译器通过表达式等处理类型修饰符的继承和传播。

我猜 NS 的人选择 ..Mutable.. 约定有几个原因。我的第一个猜测是,我相信当 NextStep 最初被开创时,C 不支持“const”,它仍然没有面向对象。更重要的是,他们希望在可变对象与不可变对象实现中进行某些优化。例如,在像 NSString 这样的不可变字符串类中,“池化”字符串可能很有用。这允许重复的字符串被原子化,并且进程可能使用更少的内存。(它有一定的缺点,但总有权衡。)

在 C++ 中,您可以通过首先了解copy-on-write来朝着相同的方向前进。据说 std::string 就是这样做的。

有趣的话题,
威尔布拉德利

于 2010-06-10T00:35:46.453 回答