LINUX.ORG.RU

Почему статической ф-ии разрешено вызывать конструктор?

 ,


1

1

Есть такой паттерн синглетон

class Singleton
{
public:
   static Singleton* Instance();
protected:
   Singleton();
private:
   static Singleton* _instance;
}
//.cpp
Singleton* Singleton::_instance = 0;
Singleton* Singleton::Instance() {
  if(_instance == 0){
     _instance = new Singleton;
  }
  return _instance;
}

И сказано, что статические ф-ии не могут обращаться к нестатическим методам класса, так вот почему статической ф-ии getInstance вдруг разрешено вызывать приватный конструктор? Ведь специально закрытым сделали, а тут лезет static. Как так?


И сказано, что статические ф-ии не могут обращаться к нестатическим методам класса

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

annulen ★★★★★ ()

Они не могут вызывать методы, требующие экземпляр класса. То есть нестатические методы. Точнее могут, но нужно получить ссылку или указатель на этот самый экземпляр откуда-то, а обычным методам this приходит по дефолту. Конструктор это очень особый метод, потому что он не требует экземпляр класса, а инициализирует новый. Так что для его вызова не требуется ничего. Вот статический метод его и может вызвать.

Private/public/protected и статические/нестатические функции это совершенно параллельные понятия.

KivApple ★★★★★ ()

потому что статическая функция тут - функция- член класса и она видит приватные члены, в том числе и конструктор. в чем проблема-то?

alysnix ()
Ответ на: комментарий от alysnix

а если б не видела, было б невозможно написать синглетон, поскольку конструктор ему надо приватным. чтобы другие сдуру не завели такую переменную иным способом, кроме взятия через Instance(). тут все чистенько, короче

alysnix ()
  • твоя версия паттерна ошибочна (уже почти десяток лет как)
  • статическая функция не может обращаться к членам класса, потому что в общем случае она не привязана к какому либо экземпляру класса.

Для справки: не статические методы всегда имеют неявный первый аргумент - указатель на экземпляр класса (this).

invy ★★★★★ ()
Последнее исправление: invy (всего исправлений: 2)

Вообще то вызывается new, который аллоцирует память и вызывает конструктор. То, что другие функции не относящиеся к классу могут new вызывать (если конструктор открыт) Вас не смущает?:-)

Статическая функция фактически внешняя для класса ф-я (у нее нет this), но она размещена в пространстве имен класса и имеет доступ к приватным членам (если дать ей указатель на экземпляр класса). New такой указатель как раз даёт.

AntonI ()
Последнее исправление: AntonI (всего исправлений: 1)

И сказано, что статические ф-ии не могут обращаться к нестатическим методам класса

Но это не правдо.

Ведь специально закрытым сделали, а тут лезет static.

static того же класса.

Dudraug ★★★★★ ()

Главное не увлекайся особо синглтонами, в современном программировании это больше считается антипаттерном чем паттерном :)

bonta ★★★ ()
Ответ на: комментарий от bonta

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

alysnix ()
Ответ на: комментарий от alysnix

Это глобальная переменная, а глобальные переменные это зло.

Во всяком случае нужны очень веские основания для их введения даже в однопоточном приложении, а уж в многопоточных вообще трэш…

AntonI ()
Ответ на: комментарий от AntonI

допустим у вас есть некий менеджер, что является «центром управления» или еще чем-то в вашей программе. он один. он глобальный обьект. файловая система - тоже обьект «глобальный». реестр виндовс, и прочее.
все что обеспечивает общую функциональность - такой глобальный обьект и вы он него не избавитесь. вот он и есть синглетон

alysnix ()

вдруг разрешено вызывать приватный конструктор

ЯННП чему ты удивляешься? Разве конструктор это метод объекта? Это метод класса, хоть и специальный.

Ведь специально закрытым сделали

Закрытым его сделали специально, чтобы объект можно было получить только через фабрику.

no-such-file ★★★★★ ()
Ответ на: комментарий от alysnix

Ещё раз, нужны ОЧЕНЬ ВЕСКИЕ ОСНОВАНИЯ для использования синглтона. Обычно, если программист уровня ТС делает такие вещи в реальном проекте - это ошибка в дизайне.

Кроме того, создать обычную глобальную переменную религия не позволяет?

AntonI ()
Ответ на: комментарий от AntonI

нужны ОЧЕНЬ ВЕСКИЕ ОСНОВАНИЯ для использования синглтона

создать обычную глобальную переменную религия не позволяет

Чёт ржу.

no-such-file ★★★★★ ()
Ответ на: комментарий от AntonI

Синглтон это не глобальная переменная. Это вообще как бы не переменная. Поэтому «глобальные переменные - зло» не применимо к синглтонам. А уж советовать использовать «просто глобальную переменную» вместо синглтона это совсем ржомба, особенно после пассажа про то что это зло.

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от no-such-file

До-до, не глобальная, особенно в ней не глобальное поле static Singleton *instance.

Ржите себе дальше, говорят это продлевает жизнь и всякое такое…

AntonI ()
Ответ на: комментарий от AntonI

Ну давай, покажи пример как обратиться к «глобальному» полю instance из другой единицы трансляции?

fluorite ★★★★★ ()
Ответ на: комментарий от AntonI

Ещё раз, нужны ОЧЕНЬ ВЕСКИЕ ОСНОВАНИЯ для использования синглтона. Обычно, если программист уровня ТС делает такие вещи в реальном проекте - это ошибка в дизайне. Кроме того, создать обычную глобальную переменную религия не позволяет?

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

приличные люди так не поступают.

alysnix ()
Ответ на: комментарий от fluorite

А в приведенном примере к полю instance из другой единицы трасляции обратиться можно?

AntonI ()
Ответ на: комментарий от alysnix

Сколько объектов stdout может быть на всю программу?

AntonI ()
Ответ на: комментарий от invy

твоя версия паттерна ошибочна (уже почти десяток лет как)

Начиная с c++11 синглтон Майерса thread-safe. Или о чём ты?

fluorite ★★★★★ ()
Ответ на: комментарий от fluorite

Тогда в чем смысл

Ну давай, покажи пример как обратиться к «глобальному» полю instance из другой единицы трансляции?

AntonI ()
Ответ на: комментарий от AntonI

Ты же утверждал, что поле _instance глобальное? Признайся, ты даже не понимаешь, что такое глобальная переменная и чем она отличается от статической в файле?

fluorite ★★★★★ ()
Последнее исправление: fluorite (всего исправлений: 2)
Ответ на: комментарий от alysnix

И как то обошлись без синглтона? Ай-яй… в С++20 надеюсь stdin/out/err обернули в синглтоны что бы все было как надо, или там в комитете нет «приличных людей»?;-)

Вы утверждаете что синглтон дескать лучше глобальной переменной. Единственное СЕМАНТИЧЕСКОЕ отличие синглтона - возможна отложенная инициализация (при первом обращении). Для обычной глобальной переменной это будет сделать сложнее/костыльнее.

AntonI ()
Ответ на: комментарий от AntonI

А в приведенном примере к полю instance из другой единицы трасляции обратиться можно?

к полю обратиться нельзя. только единица трансляции тут не причем. нельзя обратиться извне класса, даже в той же «единице трасляции». поле приватное, можно его получить только через функцию Instance(). в этом и фишка. ты можешь получить ссылку или указатель на обьект, который ты сам не сможешь создать. потому что тебе НЕ РАЗРЕШИЛИ создавать его где ни попадя.
опять же это LAZY инициализация. обьект будет физически создан, ТОЛЬКО если его попросят в первый раз. а не попросят - он не будет создан вообще.

alysnix ()
Ответ на: комментарий от no-such-file

Синглтон это не глобальная переменная

Вполне себе глобальная переменная, проблема с «static initialization order fiasco» решена, все остальные остались на месте.

annulen ★★★★★ ()
Ответ на: комментарий от fluorite

А что, глобальная переменная (пусть и со static) в единице трансляции перестает быть глобальной? Интересно отчего, от того что ее не видно из других единиц? А если я вот так сделаю

// a.hpp:

T * get_p();
// a.cpp:
static T *p;
T * get_p() { return p; }

то жизнь заиграет новыми красками и p снова станет истинно глобальной?

AntonI ()
Ответ на: комментарий от alysnix

Вы бы сменили что ник на «Капитан Очевидность»;-)

AntonI ()
Ответ на: комментарий от annulen

Вполне себе глобальная переменная, проблема с «static initialization order fiasco» решена, все остальные остались на месте.

Синглетон НЕ ГЛОБАЛЬНАЯ переменная. он может быть создан как скрытая глобальная переменная, а может и нет.
Ничто не мешает навернуть внутри Instance() любую кухню. она просто возвращает ссылку на нечто. а как ты это нечто реализовал - твое дело.

alysnix ()
Ответ на: комментарий от alysnix

Ну давайте в студию реализацию синглтона без глобальных переменных. Вообще без ниодной. Ремарка - статические поля класса тоже глобальные переменные.

AntonI ()
Ответ на: комментарий от alysnix

вообще отличайте товарищи понятие глобальной переменной - это разговор о глобальной видимости ее, и статической переменной - это разговор о том, где она аллокирована. приватная статическая переменная - не глобальна. ее видит только класс в котором она обьявлена.

alysnix ()
Ответ на: комментарий от AntonI

Нет, не станет. Кароче, читай матчасть про internal и external linkage.

fluorite ★★★★★ ()
Ответ на: комментарий от alysnix

Но все равно Instance() можно дернуть из любого места в программе и изменить состояние объекта, получая все сопутсвующие архитектурные проблемы.

annulen ★★★★★ ()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от annulen

Но все равно Instance() можно дернуть из любого места в программе и изменить состояние объекта, получая все сопуствующие проблемы дизайна.

для этого в С++ есть модификатор const :) не хочешь чтобы меняли - делай констатные методы и возвращай констатную ссылку. или указатель. лучше ссылку, потому что наличие обьекта гарантировано.

alysnix ()
Ответ на: комментарий от annulen

Но все равно Instance() можно дернуть из любого места в программе и изменить состояние объекта, получая все сопутсвующие архитектурные проблемы.

Главная фишка в другом. Синглетоном(ну или фабрикой) тебе ограничили твои очумелые ручки, и не позволили создать обьект самостоятельно. И это очень правильно.

alysnix ()
Ответ на: комментарий от alysnix

Да, read-only синглтон - это уже почти не зло, но остается проблема с юнит-тестированием, так как перед выполнением тестов он должен быть в правильном состоянии.

annulen ★★★★★ ()
Ответ на: комментарий от annulen

Да, read-only синглтон - это уже почти не зло,

А можно пример надобности такого синглтона?

Serral ()
Ответ на: комментарий от fluorite

Кароче, под термином «глобальная переменная» тут разные люди понимают разные вещи.

С семантической точки зрения глобальная переменная доступна в рантайм из любого места кода. То что при этом ее там во что то завернули (исключительно для получения доступа, без контроля за действиями с ней) или разместили в куче а не в глобальной области памяти ее не делает менее глобальной. Остальное нюансы.

AntonI ()
Ответ на: комментарий от annulen

Дык и глобальные константы это вполне себе Ъ - pi например или e;-)

AntonI ()
Ответ на: комментарий от AntonI

Но есть нюанс - глобальную константу никто никогда не может изменить после инициализации. А у синглтона могут быть френды.

annulen ★★★★★ ()
Ответ на: комментарий от AntonI

И с юнит-тестами глобальные константы тоже проблем не создают, так как их не нужно специально инициализировать

annulen ★★★★★ ()
Ответ на: комментарий от AntonI

Загруженный и распарсенный конфиг файл например.

Он может применяться для инициализации, но хранить его смысла обычно никакого нет.

Serral ()
Ответ на: комментарий от annulen

Да, read-only синглтон - это уже почти не зло, но остается проблема с юнит-тестированием, так как перед выполнением тестов он должен быть в правильном состоянии.

есть еще одна фишка с такими фабриками и синглетонами. ты можешь реализовать глухую защиту доступа к объекту. если сделать метод Instance(passcode). то есть инстанс берется с предьявлением кода доступа, секретного кода, паспорта и все такое. в зависимости от кода доступа фабрика выдает ссылку на физически разные обьекты, от невинных, юзая которые ты ничего не сломаешь, до полного контроля над чем-то.
Это нужно когда куча программеров с очумелыми ручками пишут большую общую систему из множества подсистем.

alysnix ()
Ответ на: комментарий от bonta

в современном программировании это больше считается антипаттерном чем паттерном :)

Это теми же дурными, которые бензопилу считают опасной, а не пионЭров, которые ею пользуются.

slackwarrior ★★★★★ ()
Ответ на: комментарий от invy

Для справки: не статические методы всегда имеют неявный первый аргумент - указатель на экземпляр класса (this).

именно так можно сломать кому-то «шаблон», дернув статик метод от экземпляра через точку, или через стрелку от указателя.

slackwarrior ★★★★★ ()
Последнее исправление: slackwarrior (всего исправлений: 1)
Ограничение на отправку комментариев: только для зарегистрированных пользователей