На самом деле не существует чистого, безопасного решения с нулевыми издержками, которое напрямую поддерживается языком. Многие люди довольны текущими функциями видимости, в то время как многие считают, что им не хватает.
Среда выполнения может (но не делает) сделать это различие с помощью иваров и методов. Первоклассная поддержка будет лучшей, ИМО. До этого у нас есть несколько абстракций:
Вариант A
Плохо - все видно. Я не согласен, что это хороший подход, и это не OOD (IMO). Если все видно, то ваш класс должен либо:
- поддерживают все случаи, когда клиент может использовать ваш класс (обычно неразумно или нежелательно)
- или вы предоставляете им массу правил через документацию (обновления документации, скорее всего, останутся незамеченными)
- или средства доступа не должны иметь побочных эффектов (не OOD, и часто переводятся как «не отменять средства доступа»)
Вариант B
Имеет недостатки варианта A ,, и, как и вариант A, члены могут быть доступны по ключу.
Вариант C
Это немного безопаснее. Как и все остальные, вы по-прежнему можете использовать доступ с ключом, и подклассы могут переопределять ваши методы доступа (даже если неосознанно).
Вариант D
Один из подходов к этому - написать свой класс как обертку над типом реализации. Для этого вы можете использовать тип ObjC или тип C ++. Вы можете отдать предпочтение C ++, где важна скорость (это упоминалось в OP).
Простой подход к этому будет иметь одну из форм:
// inner ObjC type
@class MONObjectImp;
@interface MONObject : NSObject
{
@private
MONObjectImp * imp;
}
@end
// Inner C++ type - Variant A
class MONObjectImp { ... };
@interface MONObject : NSObject
{
@private
MONObjectImp imp;
}
@end
// Inner C++ type - Variant B
class MONObjectImp;
@interface MONObject : NSObject
{
@private
MON::t_auto_pointer<MONObjectImp> imp;
}
@end
(Примечание: с тех пор, как это было изначально написано, появилась возможность объявлять ивары в блоке @implementation. Вы должны объявлять ваши типы C ++ там, если нет необходимости поддерживать более старые цепочки инструментов или «хрупкие» бит OS X ABI).
C ++ Вариант A не так «безопасен», как другие, потому что он требует объявления класса, видимого для клиента. В других случаях вы можете объявить и определить класс Imp в файле реализации, скрывая его от клиентов.
Затем вы можете выставить интерфейс по вашему выбору. Конечно, клиенты могут получить доступ к вашим членам, если они действительно хотят через среду выполнения. Это было бы проще для них безопасно сделать с типом ObjC Imp - среда выполнения objc не поддерживает семантику C ++ для членов, поэтому клиенты будут запрашивать UB (IOW, это все POD для среды выполнения).
Стоимость выполнения для реализации ObjC заключается в написании нового типа, создании нового экземпляра Imp для каждого экземпляра и значительном удвоении количества сообщений.
Тип C ++ практически ничего не будет стоить, кроме размещения (вариант B).
Вариант E
Другие подходы часто отделяют ivars от интерфейсов. Хотя это хорошая вещь , это также очень необычно для типов ObjC. Типы / конструкции ObjC часто поддерживают тесную связь со своими иварами и аксессуарами, поэтому вы столкнетесь с сопротивлением со стороны других разработчиков.