#c #templates #inner-classes #friend
#c #шаблоны #внутренние классы #друг
Вопрос:
Добрый вечер.
У меня следующая проблема при написании некоторого общего кода (по крайней мере, на C 11):
Рассмотрим класс с именем I
, который может быть вложен в различные классы A, B, …, N:
class A
{
protected:
friend class I;
class I
{
} i;
};
class B
{
protected:
friend class I;
class I
{
} i;
};
etc.
На самом деле I
это своего рода инструмент интерфейса, автоматически вставляемый в различные пользовательские классы A … N. Не заботьтесь о причине для этого…
Затем существует определенный класс Z, и цель состоит в том, чтобы объявить any I
другом Z, чтобы любой I
и ничто другое не могло использовать Z, в какой бы класс A … N (определенный позже) он I
не был вложен.
Если я объявлю этот способ:
class Z
{
friend class A; // <--- but I don't want to have to know this one
friend class I;
private: // creation and use of Z are restricted to tools like I
Z();
// other methods
};
Тогда это работает только для A::I
:
Из A::I::some_function()
можно создать и использовать Z, но не из B::I
ни какого другого в B … N.
Без friend class A;
ни один из I
не сможет получить доступ к Z.
- Как сделать его универсальным?
Я ищу способ написать объявление друга шаблона, предоставляющее доступ для любого, X::I
где X — параметр шаблона.
И не является параметром шаблона для, I
конечно, поскольку I
это не шаблон.
Конечно, я не хочу предоставлять доступ к какому-либо классу X, чтобы любой X::I
тоже мог получить доступ к Z !
Следующее не работает:
class Z
{
template< class X> friend class X::I;
...
};
=> ошибка: ‘I’ не является членом ‘X’
из gcc версии 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.11)
Есть представление о правильном синтаксисе? Я не нашел этого варианта использования в ссылке…
Большое спасибо, с уважением.
================= добавлено 16 августа : Уточнения:
I
Существует постоянно как часть A
(или другого), в то время как Z
это инструмент, работающий только во время определенной операции I
, которая может повторяться, затем создается новый Z
, используется, а затем удаляется каждый раз как локальный метод I
.
Также Z
имеет соответствующую полезную нагрузку, и я не хочу делать это постоянной частью каждого объекта, внедряющего I
. Например, путем создания Z
унаследованного от I
.
Комментарии:
1. Итак, если я правильно понимаю, любой класс, имеющий вложенный
I
тип, должен дружить сZ
? Без ручного указания этих классов вZ
вам потребовалось бы отражение, что в настоящее время в c невыполнимо.2. Я выделил ‘I’ жирным шрифтом, чтобы они были более заметны. @cigien: Нет, только ‘I’ внутри любого ‘X’ должен обращаться к ‘Z’, а не к самому ‘X’. Я просто хочу объявить ‘I’ другом ‘Z’ через любой внешний класс. Изначально я ожидал, что это будет работать только с именем ‘I’, но, видимо, это не так, я получаю ошибку «Z () является частным»
3. Просто короткий комментарий к вашему описанию: «Рассмотрим класс с именем I, который может быть вложен в различные классы A, B, …, N:» — это не описывает его. Существует множество именованных классов
I
, вложенных в другие классы. Их «полное» имяA::I
,B::I
и т.д.4. @Ulrich Eckhardt : Да, это автоматически вставляемый (короткий) код, объявляющий класс, который всегда именуется
I
внутри пользовательского класса,I
будучи идентичным по своей структуре (не обязательно в реализации его методов) для всех таких пользовательских классов, тогда мы могли бы вызвать его*::I
в настоящем контексте. Верно, что из-за пути это не тот же тип C , несмотря на то, что это тот же идентификатор (терминала). Вот почему я ожидаю решить проблему с объявлением друга шаблона, позволяющим изменять путь.
Ответ №1:
Вероятно, вы можете достичь того, что пытаетесь сделать, сделав I
inherit Z
и создав Z
абстрактный базовый класс (чтобы к нему нельзя было получить прямой доступ).
Что-то похожее на:
class Z
{
virtual void __() = 0;
public:
virtual ~Z() = default;
void method() { std::cout << "Method from Z" << std::endl; }
};
class A
{
friend class I;
public:
class I : public Z
{
void __() final {}
public:
static Z *make_z();
} i;
};
Z *A::I::make_z()
{
return new I();
}
int main()
{
Z *z = A::I::make_z();
z->method();
return 0;
}
Комментарии:
1. Спасибо за идею, но это вызвало бы ужасные проблемы с точки зрения срока службы. Проблема, которую я опубликовал, очень упрощена. На самом деле
I
существует постоянно как частьA
(или другого), в то время какZ
это инструмент, работающий только во время определенной операцииI
, которая может повторяться, затем создается новыйZ
, используется, а затем удаляется каждый раз как локальный методI
. ТакжеZ
имеет соответствующую полезную нагрузку, и я не хочу делать это постоянной частью каждого объекта, внедряющегоI
. Извините, я не могу сообщить подробности в комментарии, и мне не разрешено публиковать четко отформатированный ответ самому себе.