Objective-C ++中禁止使用C ++引用类型作为实例变量。我该如何解决这个问题?
答案 0 :(得分:8)
您无法合理地将引用用作实例变量,因为无法初始化实例变量,并且无法重新引用引用。
另一种选择可能是简单地使用(可能是智能的)指针。
让您更接近C ++的另一种可能性 - 就像为您的C ++成员使用PIMPL样式的成员一样:
struct CppImpl {
SomeClass& ref;
CppImpl(SomeClass& ref) : ref(ref) {}
};
@interface A : NSObject {
CppImpl* pimpl;
}
- (id)initWithRef:(SomeClass&)ref;
@end
@implementation
- (id)initWithRef:(SomeClass&)ref {
if(self = [super init]) {
pimpl = new CppImpl(ref);
}
return self;
}
// clean up CppImpl in dealloc etc. ...
@end
答案 1 :(得分:2)
格奥尔格的第一句话是完全正确的:
您无法合理地将引用用作实例变量,因为无法初始化实例变量,并且无法重新引用引用。
但我认为他的解决方案是最好的解决方案。
指针和引用之间的语义差异很小。引用本质上是一个不能为空的指针。因此,在界面中使用引用肯定是一个好主意,使nullptr
不是有效的初始化参数非常明显。但在内部,您只需存储指针:
@interface A : NSObject {
SomeClass* p;
}
- (id)initWithRef:(SomeClass&)ref;
@end
@implementation A
- (id)initWithRef:(SomeClass&)ref {
if(self = [super init]) {
p = &ref;
}
return self;
}
@end
没有(在最坏的情况下:手动)内存分配,根本没有资源处理,没有额外的间接等等.A的每个成员都可以简单地断言p != nullptr
。
答案 2 :(得分:0)
boost :: ref()可能有帮助吗?
答案 3 :(得分:0)
更通用的解决方案是使用reference_wrapper<T>
而不是自定义结构。最终结果是类似的。
然后,再次,如果您只需要存储一个成员,那么通过使用struct或者这个包装器,你没有比指针更有优势。 (谢谢Georg!)
我使用Georg的答案作为例子的起点:
// This bare interface can be used from regular Objective-C code,
// useful to pass around as an opaque handle
@interface A : NSObject
@end
// This interface can be shown to appropriate Objective-C++ code
@interface A (Private) // @interface A () if it's just for this class's .mm file
- (id)initWithRef:(SomeClass &)ref;
@property (readonly, nonatomic) SomeClass &ref;
@end
@implementation A {
reference_wrapper<SomeClass> *_refWrapper;
}
- (id)init {
// and/or throw an exception
return nil;
}
- (id)initWithRef:(SomeClass &)ref {
self = [super init];
if(self) {
_refWrapper = new reference_wrapper<SomeClass>(ref);
}
return self;
}
- (SomeClass &)ref {
// reference_wrapper<T> is implicitly convertible to T&
return *_refWrapper;
// This would also work:
// return _refWrapper->get();
}
- (void)dealloc {
delete _refWrapper;
}
@end
这个多标题模式有助于传递Objective-C代码中的不透明句柄,同时为少数人提供Objective-C ++特性(即使它只是objc类的实现)。