Re[13]: Почему нельзя предварительно объявить дружественную ф
От: so5team https://stiffstream.com
Дата: 26.09.23 05:03
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

S>>в мире есть более одной платформы. Как программной, так и аппаратной.


ЕМ>Какова доля "истинно кросс-платформенного" кода на C++ во всем объеме кода на C++?


ХЗ. В моей около тридцатилетней практике что-то около 100%. Включая ситуации, когда доступ к целевой платформе ограничен (условный SPARKstation один, а коллектив большой, и доступ к нему давался по расписанию) и большая часть разработки велась на x86 Linux с gcc. И ситуации, когда приложение разрабатывалось без планов портирования куда-либо, а потом возникала идея "вот есть такая аппаратно-программная платформа, если мы на нее портируем свой софт, то сможем заходить к потенциальным клиентам и со стороны продавцов этой платформы".

Но, подозреваю, что когда человек пишет драйвера для Windows на x86/x64, то весь мир C++ для него выглядит как прибитый гвоздями для одной платформы.

ЕМ>А если вычесть формально существующий, но не используемый сколько-нибудь активно?


Не распарсил.

ЕМ>Чем дальше задача уходит от конкретной платформы, тем меньше остается оснований делать ее на C++.


Ну да, ну да. Продавцы Qt смотрят на вас как на...
Re[7]: Почему нельзя предварительно объявить дружественную функ
От: so5team https://stiffstream.com
Дата: 26.09.23 05:13
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>>>Чем это лучше, как сделать вспомогательную функцию открытым членом класса A, и вызывать ее из класса B?


S>>Тем, что тогда ее сможет вызвать кто угодно, а не только класс B. Ваш К.О.


ЕМ>Скажите, К.О., а кто из перечисленных не сможет вызвать функцию modify_A?


Например тот, кто не имеет валидной ссылки на экземпляр B.

S>>- нужно минимизировать объем кода, который имеет доступ к потрохам класса A (т.е. до одной функции/метода);

S>>- сделать это нужно в условиях, когда перед определением класса A нельзя сделать определение класса B (которому и нужен доступ к потрохам B).

ЕМ>Верно.


Ну тогда вот это -- ""В лоб" — это объявить дружественным весь класс B, и забить на принцип минимальных прав." -- не есть решение поставленной задачи.

S>>Если вам насрать на эту задачу и вы можете просто сделать класс B другом для класса A, то зачем весь этот кипешь?


ЕМ>Вопрос, напоминаю, был не в том, как это сделать (способы решения есть разные, и все они в чем-то кривые), а в том, почему язык не допускает указания друзей-членов наперед, хотя принципиальных препятствий этому нет.


Точнее было бы сказать, что это вы не видите принципиальных препятствий. Вам ув.тов.watchmaker уже описал некоторые причины, вас не удовлетворило, вы начали вести себя в стиле "ты говоришь мне просто правду, а я ужасную хочу!"

Подумайте еще вот о чем: сейчас язык допускает либо упреждающее объявление класса (вроде class A;), либо полное определение (class A {...}). Ваше предложение о том, чтобы можно было не давая полного определения класса сделать предварительное объявление его метода в качестве друга означает, что нужно ввести еще одно состояние. Нечто вроде частично определенный класс. И, как по мне, то нафиг нам в C++ такое щасте, язык итак уже усложнен донельзя.
Re[7]: read_only ячейка
От: so5team https://stiffstream.com
Дата: 26.09.23 05:25
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>>Если у класса A слишком много друзей, то с классом A явно что-то не так.


S>Серьёзно: Если бы было ...
S>public read_only protected full_access:
S>
... то число геттеров могло бы поубавиться


Тут нужно смотреть по конкретной ситуации, а не по сферическим примерам в вакууме.
Из собственной практики могу вспомнить такой пример.
Есть у нас класс environment_t, который дает пользователю доступ к ряду публичных методов. Но внутри библиотеки нужно уметь обращаться и к закрытой части функциональности этого класса. Причем из разных мест библиотеки.

Вариант сделать все эти места (т.е. внутренние классы и функции, да и не только внутренние, некоторые публичные классы/функции в своей реализации так же должны обращаться к закрытой части environment_t) друзьями environment_t -- это прямой путь в никуда (иметь вот такие списки не есть хорошо в долгосрочной перспективе).

Поэтому проще объявить для environment_t другом отдельный внутренний класс internal_env_iface_t, который живет в специальном внутреннем пространстве имен и не предназначен для прямого использования конечным пользователем.

Конечно, в C++ нет средств полностью ограничить доступ к internal_env_iface_t. Но при уже имеющейся сложности языка я не знаю, хотел бы иметь еще и такие возможности. ИМХО, прагматичнее просто сказать "вот это руками не трогать", а кто не внял, тот ССЗБ.
Re[8]: Почему нельзя предварительно объявить дружественную функ
От: so5team https://stiffstream.com
Дата: 26.09.23 07:07
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>А может быть уже есть я.п. в которых это реализовано?


Java, например:
public class MyClass {
    public static void main(String args[]) {
        var x = new Helper();
        var y = new Helper();

        x.add(2);
        x.mul(10);
        
        y.add(3);
        y.mul(5);

      System.out.println("Sum of x+y = " + (x.current() + y.current()) );
    }
}

class Helper {
    private int x = 0;
    public void add(int d) {
        x += d;
    }
    public void mul(int d) {
        x *= d;
    }
    public int current() { return x; }
}

В MyClass использование класса Helper и его методов начинается до того, как сам класс Helper будет объявлен. Насколько я помню, это действительно в Java для классов с областью видимости package.
Re[8]: Почему нельзя предварительно объявить дружественную функ
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 26.09.23 07:23
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>как думаете, когда-нибудь требование для forward declaration в языке си++ станут необязательными?


Я даже думать не хочу о таком ужасе. Хватит и того, что в угоду вполне себе глупой концепции "interface first" добавили возможность определять данные класса после методов. Представляю, сколько это вызвало (и продолжает вызывать) матов у разработчиков компиляторов.
Re[7]: read_only ячейка
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 26.09.23 07:25
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Если бы было

S>
S>public read_only protected full_access:
S>


Я обеими руками за readonly, чтобы не плодить тривиальных геттеров. А какой смысл в full_access при наличии public?
Re[14]: Почему нельзя предварительно объявить дружественную ф
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 26.09.23 07:35
Оценка: :)
Здравствуйте, so5team, Вы писали:

ЕМ>>Какова доля "истинно кросс-платформенного" кода на C++ во всем объеме кода на C++?


S>ХЗ. В моей около тридцатилетней практике что-то около 100%.


Это наводит на мысль о том, что Вы работаете преимущественно в сфере кросс-платформенного опенсорса.

S>подозреваю, что когда человек пишет драйвера для Windows на x86/x64, то весь мир C++ для него выглядит как прибитый гвоздями для одной платформы.


Человек говорит о том, что кросс-платформенность не является (и не должна быть) сверхцелью. Это лишь одно из свойств ПО, но далеко не всегда ключевое, и далеко не всегда даже желательное.

ЕМ>>А если вычесть формально существующий, но не используемый сколько-нибудь активно?


S>Не распарсил.


Огромное количество софта, особенно опенсорсного, существует лишь потому, что его просто захотели написать — так же, как литература, поэзия, живопись и видосики.

ЕМ>>Чем дальше задача уходит от конкретной платформы, тем меньше остается оснований делать ее на C++.


S>Продавцы Qt смотрят на вас как на...


Еще скажите, что по мере развития Qt разработчики массово бросают Java, Python и подобное, и переходят на C++.
Re[8]: Почему нельзя предварительно объявить дружественную функ
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 26.09.23 07:47
Оценка:
Здравствуйте, so5team, Вы писали:

ЕМ>>кто из перечисленных не сможет вызвать функцию modify_A?


S>Например тот, кто не имеет валидной ссылки на экземпляр B.


Тот, кто не имеет экземпляра класса или указателя/ссылки на него, не сможет ничего сделать данными класса. Вытекает ли из этого, что private не имеет смысла?

S>""В лоб" — это объявить дружественным весь класс B, и забить на принцип минимальных прав." -- не есть решение поставленной задачи.


Это частное решение поставленной задаче с минимумом извращений. Городить ради этого невнятную обвязку, смысла которой я через год сам не пойму без подробных комментариев — нунах. У меня уже применяется несколько подобных кривых "решений", от которых до сих пор неуютно.

S>Точнее было бы сказать, что это вы не видите принципиальных препятствий.


А Вы видите? Если да, то в чем их принципиальность?

S>Вам ув.тов.watchmaker уже описал некоторые причины


Товарищу я давно ответил, что описанные им причины никак не относятся к обсуждаемому вопросу.

S>означает, что нужно ввести еще одно состояние. Нечто вроде частично определенный класс.


Не нужно. На степень определенности класса это вообще никак не повлияет.

S>при уже имеющейся сложности языка я не знаю, хотел бы иметь еще и такие возможности


Если б сложность языка диктовалась только необходимостью... Когда-то все данные было необходимо или определять, или объявлять до их использования. Затем это требование сняли для определений классов. Какие реальные проблемы это решило? А теперь прикиньте, насколько для этого пришлось усложнить спецификацию и реализацию компилятора.
Re[15]: Почему нельзя предварительно объявить дружественную ф
От: so5team https://stiffstream.com
Дата: 26.09.23 08:47
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>>>Какова доля "истинно кросс-платформенного" кода на C++ во всем объеме кода на C++?


S>>ХЗ. В моей около тридцатилетней практике что-то около 100%.


ЕМ>Это наводит на мысль о том, что Вы работаете преимущественно в сфере кросс-платформенного опенсорса.


Разве что последние 10 лет, и то не полностью.

Однако, к чему это? Вы пытаетесь доказать, что подавляющая часть C++ного кода изначально прибита гвоздями к одной платформе и одной версии одного компилятора?

S>>подозреваю, что когда человек пишет драйвера для Windows на x86/x64, то весь мир C++ для него выглядит как прибитый гвоздями для одной платформы.


ЕМ>Человек говорит о том, что кросс-платформенность не является (и не должна быть) сверхцелью. Это лишь одно из свойств ПО, но далеко не всегда ключевое, и далеко не всегда даже желательное.


Да это сколько угодно. Вам на другое указывают: если вы не соблюдаете стандарт в коде, то даже в рамках одной платформы вы можете получить проблемы. Просто сменив компилятор. А заставить его сменить вас смогут непреодолимые обстоятельства. Например, из-за импортозамещения в приказном порядке.

ЕМ>Огромное количество софта, особенно опенсорсного, существует лишь потому, что его просто захотели написать — так же, как литература, поэзия, живопись и видосики.


И? Вот Chrome построен на базе открытого ПО. Можно ли представить себе современный Интернет без Chrome и разработок на его основе?

ЕМ>>>Чем дальше задача уходит от конкретной платформы, тем меньше остается оснований делать ее на C++.


S>>Продавцы Qt смотрят на вас как на...


ЕМ>Еще скажите, что по мере развития Qt разработчики массово бросают Java, Python и подобное, и переходят на C++.


Вы странно интерпретируете события: массовый отказ от C++ начался более 25 лет назад. Обычные компьютеры обычных пользователей перестали тормозить уже лет 20 как, так что использование софта на Java/C#/Python/Electron/... уже не представляет проблемы для рядового пользователя. Но Qt все еще продается.

Возможно, со временем Rust отберет у C++ изрядную долю оставшегося у C++ рынка. Но пока это еще не произошло.

Так что писать в user-space на C++ есть еще достаточно резонов.
Re[7]: Почему нельзя предварительно объявить дружественную функ
От: B0FEE664  
Дата: 26.09.23 08:50
Оценка: 14 (1)
Здравствуйте, Евгений Музыченко, Вы писали:

S>>- нужно минимизировать объем кода, который имеет доступ к потрохам класса A (т.е. до одной функции/метода);

S>>- сделать это нужно в условиях, когда перед определением класса A нельзя сделать определение класса B (которому и нужен доступ к потрохам B).
ЕМ>Верно.

class A;
class B;
class OnlyA{ friend class A; private: OnlyA(){} };

class A {
  friend void modify_A(A &, B &, OnlyA);
public:
  void f(B & consumer);
private: int m_iA{0};  
};

class B {
  friend void modify_A(A &, B &, OnlyA);

public:
private: int m_iB{0};  
};

void A::f(B & b) {
  modify_A(*this, b, OnlyA{});
}

void modify_A(A & a, B & b, OnlyA) {
  // Тут есть доступ и к потрохам A, и к потрохам B.
  a.m_iA++;
  b.m_iB++;
}

int main()
{
    A a;
    B b;
    a.f(b);
  //modify_A(a, b, OnlyA{});

  return 0;
}


Можно, но зачем?
И каждый день — без права на ошибку...
Re[9]: Почему нельзя предварительно объявить дружественную функ
От: so5team https://stiffstream.com
Дата: 26.09.23 09:04
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>>>кто из перечисленных не сможет вызвать функцию modify_A?


S>>Например тот, кто не имеет валидной ссылки на экземпляр B.


ЕМ>Тот, кто не имеет экземпляра класса или указателя/ссылки на него, не сможет ничего сделать данными класса. Вытекает ли из этого, что private не имеет смысла?


Если бы не этот смайлик, я бы подумал, что вы просто тупите. А смайлик наводит на мысль, что вы тупите и гордитесь этим.

S>>""В лоб" — это объявить дружественным весь класс B, и забить на принцип минимальных прав." -- не есть решение поставленной задачи.


ЕМ>Это частное решение поставленной задаче с минимумом извращений.


Сделать весь класс B другом для A не есть решение задачи, в постановке которой присутствует "нужно минимизировать объем кода, который имеет доступ к потрохам класса A (т.е. до одной функции/метода)". Вы вместо поиска решения меняете задачу.

S>>Точнее было бы сказать, что это вы не видите принципиальных препятствий.


ЕМ>А Вы видите? Если да, то в чем их принципиальность?


Выше уже было сказано и watchmaker-ом, и мной. Тот факт, что объявляя метод другом без объявления класса B нам придется в этом объявлении указывать виртуальность этого метода (или указывать, что это static-метод). Тот факт, что у нас появляется понятие частично определенного класса.

Это все принципиально важные моменты чтобы послать подобную идею в /dev/null.

ЕМ>Товарищу я давно ответил, что описанные им причины никак не относятся к обсуждаемому вопросу.


Так я и говорю, вам ужасная правда нужна, простой вам недостаточно.

S>>означает, что нужно ввести еще одно состояние. Нечто вроде частично определенный класс.


ЕМ>Не нужно. На степень определенности класса это вообще никак не повлияет.


Правда?
class B;

class A {
  friend void B::f(int a) const;
  ...
};

void g(B & b) // Это допустимо и без полного определения B.
{
  b.f(0); // Ведь мы знаем про наличие f(int) в B.
  ...
}


Все еще никак не влияет?

S>>при уже имеющейся сложности языка я не знаю, хотел бы иметь еще и такие возможности


ЕМ>Если б сложность языка диктовалась только необходимостью... Когда-то все данные было необходимо или определять, или объявлять до их использования.


Разве что во времена C, когда C++ еще не было.

ЕМ>Затем это требование сняли для определений классов. Какие реальные проблемы это решило?


Например, вот такие:
class Demo {
  void f() {
    ...
    this->g();
  }
  void g() {
    ...
  }
  ...
};

Demo::f() может вызывать Demo::g() еще до объявления g(). Выйти из этого можно было бы так:
class Demo {
  void f(); // Никакого inline в определении класса.
  void g(); // Никакого inline в определении класса.
  ...
};
void Demo::f() {
  this->g(); // Теперь OK, т.к. определение класса было выше.
}
void Demo::g() {
  ...
}

что сделало бы использование С++ менее удобным.

А теперь прикиньте, насколько для этого пришлось усложнить спецификацию и реализацию компилятора.
Re[16]: Почему нельзя предварительно объявить дружественную ф
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 26.09.23 09:14
Оценка: :)
Здравствуйте, so5team, Вы писали:

S>Вы пытаетесь доказать, что подавляющая часть C++ного кода изначально прибита гвоздями к одной платформе и одной версии одного компилятора?


Я пытаюсь объяснить, что и кросс-платформенность, и кросс-компиляторность — это просто возможности языка. Которые могут быть использованы в конкретном ПО, а могут и не быть.

В истории и науки, и техники было множество попыток обобщения и стандартизации. До определенных пределов они, как правило, давали преимущества, но затем нередко начинали создавать проблемы. То есть, далеко не всегда разумно пытаться свести все к одному стандарту.

S>если вы не соблюдаете стандарт в коде, то даже в рамках одной платформы вы можете получить проблемы. Просто сменив компилятор.


Проблемы случаются регулярно — при смене железа, ОС, окружения, сети и прочего. Привести все это к полному единообразию невозможно, всегда приходится что-то менять и дорабатывать. Компилятор — лишь одна из частей этой системы. При разумном подходе он создает не больше проблем, чем все остальное.

S>Chrome построен на базе открытого ПО. Можно ли представить себе современный Интернет без Chrome и разработок на его основе?


Лучше было бы, если б было можно. То, что этого нельзя представить, ни разу не положительная сторона.

S>Обычные компьютеры обычных пользователей перестали тормозить уже лет 20 как


Пользователи обычных компьютеров смотрят на Вас с недоумением. Или Вы о тормозах при вводе текста в простейшие редакторы типа "блокнот"?

S>Но Qt все еще продается.


И еще долго будет продаваться. Но не будет победно шествовать по планете.

S>писать в user-space на C++ есть еще достаточно резонов.


Я говорю не о том, что резонов недостаточно. Скорее о том, что доскональное соблюдение стандарта не избавляет от геморроя с обеспечением совместимости с конкретными платформами. А проблемы "тут надо подшаманить под новую версию макоси", "там надо добавить особенности нового монитора" возникают гораздо чаще, чем проблемы при смене компилятора.

Поэтому ко всему нужно относиться разумно, а не чисто формально.
Re[10]: Почему нельзя предварительно объявить дружественную функ
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 26.09.23 11:03
Оценка:
Здравствуйте, so5team, Вы писали:

S>Сделать весь класс B другом для A не есть решение задачи, в постановке которой присутствует "нужно минимизировать объем кода, который имеет доступ к потрохам класса A (т.е. до одной функции/метода)". Вы вместо поиска решения меняете задачу.


Коню понятно, что упомянутая задача не является ни первичной, ни даже необходимой. Первичная задача — обеспечить разумную степень безопасности кода, она и не меняется. А конкретный элемент этой задачи — минимизация кода с повышенными правами — в данном случае приходится признать не реализуемым адекватными методами. Неадекватных же я применять не хочу, они того не стоят.

S>объявляя метод другом без объявления класса B нам придется в этом объявлении указывать виртуальность этого метода (или указывать, что это static-метод).


Зачем? Это все относится сугубо к вызову функции, в котором здесь необходимости не возникает. А если бы и требовалось, то в чем проблема? Коли уж сложилась ситуация, когда во friend недостаточно указать только имя, то какая печаль с того, что прототип придется указывать со всеми атрибутами?

S>что у нас появляется понятие частично определенного класса.


Я уже говорил, что не появится, нет такой необходимости. Было бы лишь объявление существования класса и наличия в нем функции с определенной сигнатурой, ничего больше.

С чего бы вдруг

S> friend void B::f(int a) const;


стало достаточным для

S> b.f(0);


? Кто поставил такую задачу? Я ее не ставил.

ЕМ>>Когда-то все данные было необходимо или определять, или объявлять до их использования.


S>Разве что во времена C, когда C++ еще не было.


Насколько я помню, этого не было в ранних реализациях C++.

S> void f(); // Никакого inline в определении класса.


Почему никакого? Ничто не мешало использовать inline в объявлении функции, в качестве атрибута "реализацию этой функции желательно инлайнить". Все равно эти вопросы решаются генератором кода, который может работать, как ему удобно.
Re[11]: Почему нельзя предварительно объявить дружественную функ
От: so5team https://stiffstream.com
Дата: 26.09.23 11:23
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

S>>Сделать весь класс B другом для A не есть решение задачи, в постановке которой присутствует "нужно минимизировать объем кода, который имеет доступ к потрохам класса A (т.е. до одной функции/метода)". Вы вместо поиска решения меняете задачу.


ЕМ>Коню понятно, что упомянутая задача не является ни первичной, ни даже необходимой.


Евгений, ну тут же все ходы записаны:

Я так понял, что решается следующая задача:

— нужно минимизировать объем кода, который имеет доступ к потрохам класса A (т.е. до одной функции/метода);
— сделать это нужно в условиях, когда перед определением класса A нельзя сделать определение класса B (которому и нужен доступ к потрохам B).


Что вы и подтверждаете:

Верно.


Какая каша у вас в голове никому здесь не ведомо (возможно даже и вам), потому что вы там еще держали и не рассказали -- хз. Для того, чтобы было вами подтверждено решение есть.

S>>объявляя метод другом без объявления класса B нам придется в этом объявлении указывать виртуальность этого метода (или указывать, что это static-метод).


ЕМ>Зачем? Это все относится сугубо к вызову функции, в котором здесь необходимости не возникает. А если бы и требовалось, то в чем проблема? Коли уж сложилась ситуация, когда во friend недостаточно указать только имя, то какая печаль с того, что прототип придется указывать со всеми атрибутами?


Такая, что мы начинаем делать частичное описание класса.

S>>что у нас появляется понятие частично определенного класса.


ЕМ>Я уже говорил, что не появится, нет такой необходимости.


Вы много херни говорите.

ЕМ>С чего бы вдруг


S>> friend void B::f(int a) const;


ЕМ>стало достаточным для


S>> b.f(0);


ЕМ>?


Да потому, что это согласуется вот с таким, например (цинк):
#include <utility>
#include <iostream>

class Demo {
    int m_a;

    friend void swap(Demo & a, Demo & b) noexcept;

    friend std::ostream & operator<<(std::ostream & to, const Demo & v);

public:
    Demo() : m_a{42} {}

    void change(int v) { m_a = v; }
};

int main() {
    Demo a, b;
    std::cout << a << b << std::endl;
    a.change(50);
    b.change(60);
    std::cout << a << b << std::endl;
    swap(a, b);
    std::cout << a << b << std::endl;
}

void swap(Demo & a, Demo & b) noexcept {
    using std::swap;
    swap(a.m_a, b.m_a);
}

std::ostream & operator<<(std::ostream & to, const Demo & v) {
    return (to << v.m_a);
}

Обратите внимания, что вызовы swap и operator<< для экземпляров Demo стали возможны потому, что в определении Demo для них есть декларации (но определения даны уже после использования внутри main).

ЕМ>Кто поставил такую задачу?


Это естественным образом проистекает из того, что мы начинаем делать частичное описание класса.

ЕМ>>>Когда-то все данные было необходимо или определять, или объявлять до их использования.


S>>Разве что во времена C, когда C++ еще не было.


ЕМ>Насколько я помню, этого не было в ранних реализациях C++.


А я вот не помню, чтобы этого в C++ не было.

S>> void f(); // Никакого inline в определении класса.


ЕМ>Почему никакого?


Потому, что написано что inline в определении класса.
Re[8]: private nested class
От: Sm0ke Россия ksi
Дата: 26.09.23 11:28
Оценка:
Здравствуйте, so5team, Вы писали:

S>Конечно, в C++ нет средств полностью ограничить доступ к internal_env_iface_t. Но при уже имеющейся сложности языка я не знаю, хотел бы иметь еще и такие возможности. ИМХО, прагматичнее просто сказать "вот это руками не трогать", а кто не внял, тот ССЗБ.


Привэйт нэстед класс

struct nest
{
private:
  struct hidden {};
};

int main()
{
  nest::hidden v; // error C2248: 'nest::hidden': cannot access private struct declared in class 'nest'
  return 0;
}


Also: Out of class nested struct definition

struct nest
{
private:
  struct hidden_1;
  struct hidden_2;
  struct hidden_3;

public:
  static void fn_test();
};

struct nest::hidden_1 {};
struct nest::hidden_2 { hidden_1 data; };
struct nest::hidden_3 {};

void nest::fn_test()
{
  hidden_2 obrabotchik;
}

int main()
{
  nest::fn_test();
  return 0;
}


Keyword 'friend' was used zero times in samples above
Re[8]: read_only ячейка
От: Sm0ke Россия ksi
Дата: 26.09.23 11:37
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

S>>
S>>public read_only protected full_access:
S>>


ЕМ> ... А какой смысл в full_access при наличии public?


Чтобы можно было уточнить для мемберов ниже — какой же к ним доступ из derived классов, а какой из внешки.
public read_only protected read_only:


--

private: это просто private

(вроде логично, что есть const — и private read_only: выглядит лишним)
Отредактировано 26.09.2023 11:39 Sm0ke . Предыдущая версия .
Re[9]: private nested class
От: so5team https://stiffstream.com
Дата: 26.09.23 12:46
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>>Конечно, в C++ нет средств полностью ограничить доступ к internal_env_iface_t. Но при уже имеющейся сложности языка я не знаю, хотел бы иметь еще и такие возможности. ИМХО, прагматичнее просто сказать "вот это руками не трогать", а кто не внял, тот ССЗБ.


S>Привэйт нэстед класс

S>Also: Out of class nested struct definition
S>Keyword 'friend' was used zero times in samples above

Не уверен, что вы поняли меня, но уверен, что не понял вас.
Re[10]: private nested class
От: Sm0ke Россия ksi
Дата: 26.09.23 14:04
Оценка:
Здравствуйте, so5team, Вы писали:

S>Не уверен, что вы поняли меня, но уверен, что не понял вас.


Это был мой ответ на Часть вашего сообщения:

Есть у нас класс environment_t, который дает пользователю доступ к ряду публичных методов. Но внутри библиотеки нужно уметь обращаться и к закрытой части функциональности этого класса. Причем из разных мест библиотеки.

Вариант сделать все эти места (т.е. внутренние классы и функции, да и не только внутренние, некоторые публичные классы/функции в своей реализации так же должны обращаться к закрытой части environment_t) друзьями environment_t -- это прямой путь в никуда (иметь вот такие списки не есть хорошо в долгосрочной перспективе).

Поэтому проще объявить для environment_t другом отдельный внутренний класс internal_env_iface_t, который живет в специальном внутреннем пространстве имен и не предназначен для прямого использования конечным пользователем.


Отдельный внутренний класс internal_env_iface_t можно поместить в private: часть другого класса.
Таким образом можно разграничить использование этого internal_env_iface_t

Далее вы писали:

Конечно, в C++ нет средств полностью ограничить доступ к internal_env_iface_t.


В си++ есть такая возможность. В этом может помочь nested classes
https://en.cppreference.com/w/cpp/language/nested_types
Re[11]: private nested class
От: so5team https://stiffstream.com
Дата: 26.09.23 14:52
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Здравствуйте, so5team, Вы писали:


S>>Не уверен, что вы поняли меня, но уверен, что не понял вас.


S>Отдельный внутренний класс internal_env_iface_t можно поместить в private: часть другого класса.

S>Таким образом можно разграничить использование этого internal_env_iface_t
S>В си++ есть такая возможность. В этом может помочь nested classes
S>https://en.cppreference.com/w/cpp/language/nested_types

Вот это и заставляет меня думать, что вы не поняли меня.
Если делать internal_env_iface_t закрытым, то чтобы дать к нему доступ из разных мест придется эти разные места прописывать в качестве друзей. А именно этого и хочется избежать.
Re[5]: Почему нельзя предварительно объявить дружественную функ
От: B0FEE664  
Дата: 26.09.23 15:28
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

S>>Какие-то странные поиски того, чего нет, когда можно решить "в лоб":

ЕМ>Это ж тоже кривой костыль. Чем это лучше, как сделать вспомогательную функцию открытым членом класса A, и вызывать ее из класса B?

Судя по этому замечанию, вы задаёте не тот вопрос, на который хотите получить ответ. Правильно ли я понимаю, что вы хотите объявить другом класса закрытый (приватный) метод другого класса?
И каждый день — без права на ошибку...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.