| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Странная проблема с реализацией синглтон-класса |
| Автор: Alpher 5.2.2007, 17:01 | ||||||
| Доброго времени суток, уважаемые! Столкнулся со следующей проблемой и туплю уже пару дней: (те вещи, которые к делу не относятся, для краткости я опустил) Файл Singleton.h
Файл LibManager.h
Файл LibManager.cpp
Компилятор (MSVC8) выдает следующее: warning C4661: 'LibManager *Singleton<T>::_glob' : no suitable definition provided for explicit template instantiation request Ну и линкер, соответственно: error LNK2001: unresolved external symbol "protected: static class PlatformManager * PlatformManager::_glob" ..... Никак не могу понять, где косяк-то? Определение для _glob ведь присутствует... |
| Автор: archimed7592 5.2.2007, 17:11 | ||
| не пойму че здесь написано почему бы не сделать что-то типа
|
| Автор: Любитель 5.2.2007, 17:44 | ||||
| Alpher, у тебя код честно говоря напоминает принцип - чтоб враг не понял. По делу - почему в принципе инитить в ноль должен наследник??? Логичней вместо указателя иметь в предке протектед статик метод:
Инициализация будет выполнена при первом вызове метода (правило инициализация локальных статик-переменных). Добавлено @ 17:47 А то что ты хотел пишется так по идее:
Заметь - разные вещи. |
| Автор: Alpher 5.2.2007, 18:23 | ||
Да, логичней. В случае, если наследник один. Если их много и статический указатель на экземпляр будет реализован в предке, то (как я понимаю, т.е. IMHO |
| Автор: Любитель 5.2.2007, 18:39 | ||||
| Пару примеров:
Где бы ты не инитил field он будет один и тот же!!!
A<B> и A<C> - два разных типа. У них будут два разных field. A - это вовсе не тип, это шаблон типа. У A<B> и B будет один field, потомучто B наследует от A<B>, но у A<C> и C - другой. |
| Автор: Alpher 5.2.2007, 18:49 | ||
Виноват, совсем забыл, что родитель - шаблонный В общем, это - выход Но все же, почему же приведенная мной конструкция не собирается? (Уже из чисто спортивного интереса В рамках одного модуля - все ок, а когда подключаю к приложению - вопит линкер. Не понятно, почему он вопит, т.к. в самом приложении _glob не используется и приложению должно быть фиолетово, экспортируется оно или нет... |
| Автор: Любитель 5.2.2007, 18:54 |
| Я выше писал - читай внимательно. Заметь, что LibraryManager и Singleton<LibraryManager> - два разных класса. И первый у тебя нигде явно не инстансируются, посему инит его полей (хотя стати поля у них и одни и те же) невозможен. |
| Автор: Alpher 5.2.2007, 19:07 | ||
Сейчас попробовал: LibraryManager *LibraryManager::_glob = 0; и template<> LibraryManager *Singleton<LibraryManager>::_glob = 0; дают абсолютно одинаковые результаты (в смысле, тот же самый ворнинг при компиляции и те же ошибки при линковке) |
| Автор: Любитель 5.2.2007, 19:09 |
| Не знаю тогда - без компилера не берусь гадать. |
| Автор: Alpher 5.2.2007, 19:15 |
Ладно, на досуге поковыряю. Если разберусь - закину причины и решение. P.S. За совет - спасибо |
| Автор: Vyacheslav 5.2.2007, 19:23 |
| А вообще весьма любопытная концепция синглтона Обычно смысл его в том, чтобы гарантировно обеспечить создание единственного экземпляра: второй просто создать невозможно. А у Вас при создании второго, а содать его можно, гарантированый вылет программы через assert при дебажной сборке и просто вылет при релизной. |
| Автор: Alpher 5.2.2007, 19:38 | ||
Конструктор/деструктор наследника пока висят в public для дебажных целей. Когда допишу класс, который будет собирать все синглтоны для использования приложением (и будет френдом для этих синглтонов), перенесу в protected Смысл моих мытарств заключается в том, чтобы централизованно создать экземпляры различных синглтонов, а потом их использовать из любого места программы через класс-ядро. Т.е. что-то вроде: Core::Inst().GetLibManager().doSomething(); |
| Автор: Vyacheslav 5.2.2007, 19:53 | ||
И что это даст?
То есть при разработке Вашей программы нужно всегда помнить о том, что прежде чем обратиться к чему либо, нужно проделать процедуру инициализации? Но тогда зачем это называть красивыми словом Singleton. Тогда проще класс с набором статических полей, проинициализировать их с помощью того же статического метода и обращаться к ним через теже статические методы. |
| Автор: Alpher 5.2.2007, 21:23 | ||
Не совсем так. Красивое слово Singleton было выбрано, т.к. оно короче, чем PseudoSingleton Инициализация экземпляров происходит единовременно при инициализации класса-ядра. Пользователь может обращаться к ним только через Core::Inst().getЧтоНибудь().doЧтоНибудь() или ЧтоНибудьКласс::Inst().doЧтоНибудь() Насчет статических полей и методов: В случае одного уровня наследования это действительно было бы проще и удобней. В моем случае требуется, грубо говоря, обеспечить возможность наследовать от производных (по отношению к Singleton) классов еще какие-либо, причем совершенно произвольно. Т.е., скажем: class LibManager : public Singleton<LibManager> class PluginManager : public LibManager, public PluginFunctions class RichPluginManager : public PluginManager, public CoolFunctions и т.п. Сомневаюсь, что в случае со статическими полями и методами в LibManager это было бы удобно. Городить темплейты на все и вся, как мне кажется, здесь нецелесообразно. Потом, в Т.З. указана возможность наращивания функционала, т.е. появления каких-либо не предусмотренных сейчас классов. В моем случае нужно перегрузить только Inst() и Ref(), а также определить _glob. P.S. Согласен, без определения _glob в потомках можно обойтись Добавлено @ 21:36 Кстати, нашел причину первоначальной проблемы Банально, в хедере, где определяется _UT_EXPORT была опечатка и оно компилилось как __declspec(dllimport) Сейчас конструкция, приведенная в первом посте отлично работает. |
| Автор: Alpher 7.2.2007, 00:47 | ||||
| Поковырялся на досуге. Вот настоящий синглтон (для Вячеслава Создается при первом обращении, доступ к _glob есть только через Inst() и Ref() (даже у самого класса Создать/уничтожить через new/delete также нельзя... Singleton.h
SampleClass.h
|