_vadim_ |
Отправлено: 02.06.2004, 22:14 |
|
Ученик-кочегар
Группа: Участник
Сообщений: 18
|
Как вызывать функцию-элемент класса, чтобы линкер потом не ругался?
Вот пример:
class Global
{
private:
static int glavset;
//Закрытый конструктор
Global();
public:
static void Setglavset(int Newglavset) {glavset = Newglavset;}
static int Getglavset() {return glavset;}
};
А при вызове фунтций, например: Global::Setglavset(1);
Линкер обзываетя:
[Linker Error] Unresolved external 'Global::glavset' referenced from D:\TEMPPROG\FCH.OBJ
Непонимаю! Где собака порылась?
Отредактировано _vadim_ — 02/06/2004, 23:17 |
|
timson |
Отправлено: 03.06.2004, 06:57 |
|
Станционный диспетчер
Группа: Участник
Сообщений: 82
|
Нельзя инициализировать статическое член-данное в теле класса, а также в член функциях..
инициализировать можно только так:
class Global
{
private:
static int glavset;
...
public:
...
};
int Global::glavset = 32;
и только так.. и всего же один раз.. так что тупо..
и вообще со Static'ом столько парки, париться да праиться придется..
и вот эта переменная будет одна для всех объектов данного класса..
так что нужны другие варианты..
|
|
_vadim_ |
Отправлено: 03.06.2004, 14:04 |
|
Ученик-кочегар
Группа: Участник
Сообщений: 18
|
Да, но функции то тоже статические.
А пременные мне эти нужны, чтобы к ним можно было обращаться из разных частей программы, проинициализировав их один раз.
Т.е. этот класс подразумевался как модуль-хранилище глобальных переменных.
А на твой пример, ругается уже не линкер, а компилятор:
[C++ Error] fzach.cpp(31): E2089 Identifier 'glavset' cannot have a type qualifier
Вопрос остается открытым. |
|
timson |
Отправлено: 03.06.2004, 15:44 |
|
Станционный диспетчер
Группа: Участник
Сообщений: 82
|
я там забыл дописать, и ты в примере не заметил, что static инициализировать можно только ВНЕ любых функции, только как обявление..
выкинь эту затею со статиком, он не для таких целей
я сам даже не нашел хорошего применения в объектном программировании, в С он область видимости показывал, только в том модуле видим..
как-то я столкнулся с ним, мне нужен был указатель на член-функцию класса вида void (*f)(), хотел отдать на выполнение потоку.. столько парился.. и нашел выход: сделал подругому без Static за пару Мин...
а нафига тебе закрытый конструктор??
че-то ты замутил не так: полез в карбюратор через глушитель..
делай все просто, убери везде этот Static, если хочешь флаг приделай, чтобы инициализировать один раз..
а объект класса объявляй глобально (как форма объявляется TForm *Form1), и инклудь этот модуль где надо..
|
|
olegenty |
Отправлено: 03.06.2004, 15:59 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
я для хранения очень уж глобальных переменных, всего лишь написал бы компонент невизуальный (бонус — редактирование свойств в дизайн-тайм + возможность сохрания в реестр/ини любым компонентом, для этого предназначенным), дибо DataModule, насоздавал там свойств и методов, и работай... (я делал и то и другое, всё работает, оч. удобно)
не стоит усложнять себе жизнь...
|
|
_vadim_ |
Отправлено: 03.06.2004, 17:08 |
|
Ученик-кочегар
Группа: Участник
Сообщений: 18
|
Ок, буду пробовать другие пути.
to timson: Закрытый конструктор нужен чтобы был. Но как ты наверное заметил он не реализован, следовательно инициализация не возможна.
to All: Почему я хотел сделать, через статик, потому, что для такого класса не требуется наличие объекта этого класса. Вообще имхо очень удобно.
Но! Я все равно не понял, почему ругается именно линкер?!
И еще, я ведь не инициализирую переменную непосредственно. Ее инициализация происходит внутри класса при вызове функции-элемента ЭТОГО класса. Обьясните плиз, для тех кто на бронепоезде. |
|
timson |
Отправлено: 04.06.2004, 07:08 |
|
Станционный диспетчер
Группа: Участник
Сообщений: 82
|
да ты не понял..
я же говорил:
- Нельзя инициализировать статическое член-данное в теле класса, а также в член функциях..
- инициализировать можно только ВНЕ любых функции, только как обявление..
в теле функции НЕЛЬЗЯ!!!
static в классах очень ограниченная вещь.
инициализация происходит на этапе компиляции, никак не в run-time.
ты должен явно указать присвоение глобально!! и никак подругому, и только один раз:
int Global::glavset = 32;
тоже самое что и делать
#define glavset 32
просто внутри класса, поэтому доступ не простой, а через явное указание имени класса Global::glavset
а линкер ругается, потому что со static'ом работать так нельзя...
без переменных нельзя (если можно, то не красиво..)
|
|
olegenty |
Отправлено: 04.06.2004, 07:24 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
я статиком пользовался в другом случае — он выполняет роль namespace — утилитный класс.
другое применение — статический wrapper на какой-нибудь COM интерфейс, который принимает нужные параметры, отрабатывает и возвращает нужный результат. весьма применимо при написании, например, сервисов, или ядер...
|
|
xTrim |
Отправлено: 04.06.2004, 07:30 |
|
Машинист паровоза
Группа: Участник
Сообщений: 208
|
если QUOTE | пременные мне эти нужны, чтобы к ним можно было обращаться из разных частей программы, проинициализировав их один раз | то можно воспользоваться паттерном Singleton (Гамма "приемы ОО програмирования") и его реализацией, допустим библиотекой Loki
|
|
AVC |
Отправлено: 04.06.2004, 12:57 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
QUOTE (_vadim_ @ писал) |
class A
{
private:
static int FPrm1;
public:
static int GetPrm1(void ) {return FPrm1;}
static void SetPrm1(int p) {FPrm1 = p; }
};
Но! Я все равно не понял, почему ругается именно линкер?!
|
Вопрос зацепил так, что потратил на него пол дня. Сам такого не делаю и вам не советую — ещё Страуструп писал "идентификатор static — однин из наиболее перегруженных в C и C++". Но с другой стороны конструкция не противоречит языку — так что дело принципа. Пришлось даже потревожить Turbo C++ (сколько на нем писано). Там все работает правильно, а вот в C++Builder любое описание static член класса, в том числе и у VCL классов, ставит Link'ер в тупик. Обмануть не удалось. То ли глюк разработчиков, то ли требуется какая то хитрая инструкция макроязыка. |
|
_vadim_ |
Отправлено: 04.06.2004, 13:20 |
|
Ученик-кочегар
Группа: Участник
Сообщений: 18
|
Но с другой стороны конструкция не противоречит языку — так что дело принципа.
Вот и я про то-же
А Singleton, кстати ведь тоже пользуется статиком:
class Singleton
{
public:
static Singleton& Instance();
protected:
Singleton();
};
Singleton& Singleton::Instance()
{
static Singleton* NewSingleton = new Singleton();
return *NewSingleton;
}
Разве на такую реализацию линкер ругаться не будет?
Отредактировано _vadim_ — 04/06/2004, 14:23 |
|
AVC |
Отправлено: 04.06.2004, 13:24 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
Нет он ругается на static member а не не member function. |
|
_vadim_ |
Отправлено: 04.06.2004, 15:16 |
|
Ученик-кочегар
Группа: Участник
Сообщений: 18
|
Всем спасибо за участие.
Из ваших ответов и собственных попыток, я сделал вывод, что статик сам по себе вещь удобная во многих случаях. Но! в реализации борланда статиком лучше не пользоваться. |
|
Asher |
Отправлено: 04.06.2004, 15:57 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Да нормальная реализация. Работает без проблем — главное правильно пользоваться. например ка timson писал
От MS-реализации отличается только местом инициализации.
|
|
AVC |
Отправлено: 04.06.2004, 16:16 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
QUOTE | Да нормальная реализация |
Где же нормальная.
Строим в TurboC++
CODE |
class A
{
private:
static int FPrm1;
public:
static int GetPrm1(void ) {return FPrm1;}
static void SetPrm1(int p) {FPrm1 = p; }
};
void main (void)
{
for(int i=0; i<10; i++)
{ A::SetPrm1(A::GetPrm1()+1);
printf("%2.2d %5.5d\n", i, A::GetPrm1());
}
}
|
работает
Строим в C++Builder
CODE |
class A
{private:
static int FPrm1;
public:
static void SetPrm1(int p) {FPrm1 = p; }
static int GetPrm1(void) {return FPrm1;}
};
void __fastcall TForm1::Button2Click(TObject *Sender)
{
A::SetPrm1(A::GetPrm1() + 1);
Memo1->Lines->Add(A::GetPrm1());
}
|
не работает. Компилятор порождает глобальный символ A::FPrm1 а линкер, вполне закономерно, его не видит.
Какие нужно внести изменения что бы код работал в стройке?
|
|
Asher |
Отправлено: 04.06.2004, 16:39 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Согласно Страуструпу, "Язык программирования С++" специальное издание 10.2.4. статические члены. стр 274, Статические члены должны быть гдето определены.
в нашем случае, после описания класса следует добавить
int A::FPrm1 = 0;//Инициализация статического члена
Просто похоже TurboC++ делал это за вас
|
|
AVC |
Отправлено: 04.06.2004, 16:55 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
Опс
Отредактировано AVC — 04/06/2004, 17:00 |
|