Иногда, понятие C++ конфиденциальности просто экранирует меня :-)
class Foo
{
struct Bar;
Bar* p;
public:
Bar* operator->() const
{
return p;
}
};
struct Foo::Bar
{
void baz()
{
std::cout << "inside baz\n";
}
};
int main()
{
Foo::Bar b; // error: 'struct Foo::Bar' is private within this context
Foo f;
f->baz(); // fine
}
С тех пор Foo::Bar
private
, Я не могу объявить b
в main
. Все же я могу назвать методы от Foo::Bar
очень хорошо. Какого черта это позволяется? Это было несчастным случаем или дизайном?
О, ожидайте, это поправляется:
Foo f;
auto x = f.operator->(); // :-)
x->baz();
Даже при том, что мне не разрешают назвать тип Foo::Bar
, это работает просто великолепно с auto
...
Noah записал:
имена типов, определенные в рамках определения класса, не могут использоваться вне их класса без квалификации.
Только для забавы, вот то, как можно достигнуть тип снаружи:
#include <type_traits>
const Foo some_foo();
typedef typename std::remove_pointer<decltype( some_foo().operator->() )>::type Foo_Bar;
Пытаюсь найти что-нибудь в стандарте, которое подробно объясняет это, но я не могу. Единственное, что я могу найти, это 9.9:
Имена типов подчиняются точно таким же правилам области видимости, как и другие имена. В частности, имена типов, определенные в определении класса, не могут использоваться вне своего класса без уточнения.
По сути, имя Foo :: Bar является частным для Foo, а не определение. Таким образом, вы можете использовать Bars вне Foo, вы просто не можете ссылаться на них по типу, поскольку это имя является частным.
Правила поиска по именам для членов также, по-видимому, имеют некоторое влияние на это. Я не вижу ничего, что конкретно ссылается на «вложенный класс», и поэтому им не было бы позволено (если я не могу найти что-либо на самом деле из-за того, что этого нет).
Я не могу дать полный ответ, но, возможно, это отправная точка. Спецификация C++ 1998 включает следующий пример кода в параграф 11.3 [class.access]
(стр. 175):
class A
{
class B { };
public:
typedef B BB;
};
void f()
{
A::BB x; // OK, typedef name A::BB is public
A::B y; // access error, A::B is private
}
В этом примере частный тип "публикуется" через публичный typedef
. Хотя это не то же самое, что публикация типа через сигнатуру функции-члена, это похоже.
Думаю, это сделано намеренно. Вы не можете явно создать экземпляр Foo :: Bar
, но его можно вернуть из функций-членов, а затем передать его другим функциям-членам. Это позволяет скрыть детали реализации вашего класса.