2010-04-30 62 views

回答

7

不能合理使用作爲實例變量的引用,因爲沒有辦法來初始化實例變量和引用不能被重新插拔一下。

另一種可能是簡單地使用(可能是智能)指針來代替。

,讓你更接近C++的另一種可能性 - 樣的行爲是使用PIMPL風格的成員你的C++成員:

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 
+0

是的,就是這樣! – 2010-04-30 17:39:09

+0

我不明白爲什麼你不只是存儲一個指向SomeClass本身的指針。引用和指針之間的區別(大部分)是您的界面完美傳輸的語義之一。看到我的答案。 – Sebastian 2015-08-24 10:53:15

+0

@Sebastian如果你只有一個成員初始化(你多久只有一個成員?),這是沒有意義的。如果您初始化多個成員並希望返回適當的確定性行爲,這會變得很有趣。 FWIW,我提到了指針和這種方法作爲可能的選擇。 – 2015-08-24 12:18:48

0

boost :: ref()可能有幫助嗎?

+0

不是真的 - 'reference_wrapper '沒有默認的構造函數,你不能初始化實例變量。 – 2010-04-30 16:57:30

0

一個更通用的解決方案是使用reference_wrapper<T>而不是自定義結構。最終結果是相似的。

話又說回來,如果你只需要存儲一個成員,你不能用無論是結構還是這個包裝要越過指針太大的優勢。 (感謝喬治!)

我用喬治的回答爲出發點的例子:

// 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類的實現)。

+0

爲什麼不直接在這裏存儲(可能是智能)指針實例?在這種情況下,我不認爲這個包裝會給你帶來什麼。 – 2014-04-02 11:27:31

+0

爲什麼不呢。想想看,在實際上和例子一樣簡單的情況下,我通常只是存儲一個指針。 – 2014-04-02 14:07:02

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

+0

如果您可以修改需要您斷言/檢查一次的選項,那麼斷言A中的每個成員似乎都很麻煩並且容易出錯。 – 2015-08-24 12:25:39

+0

這與斷言您的pimpl指針在每個成員中仍然有效沒有什麼不同。也許它太偏執了,但它適用於這兩種解決方案。 – Sebastian 2015-08-24 13:11:00