C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Функция-элемент класса
_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

Непонимаю! Где собака порылась? sad.gif

Отредактировано _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
Вопрос остается открытым. wink.gif
timson
  Отправлено: 03.06.2004, 15:44


Станционный диспетчер

Группа: Участник
Сообщений: 82



я там забыл дописать, и ты в примере не заметил, что static инициализировать можно только ВНЕ любых функции, только как обявление..
выкинь эту затею со статиком, он не для таких целей
я сам даже не нашел хорошего применения в объектном программировании, в С он область видимости показывал, только в том модуле видим..
как-то я столкнулся с ним, мне нужен был указатель на член-функцию класса вида void (*f)(), хотел отдать на выполнение потоку.. столько парился.. и нашел выход: сделал подругому без Static за пару Мин...

а нафига тебе закрытый конструктор??

че-то ты замутил не так: полез в карбюратор через глушитель..

делай все просто, убери везде этот Static, если хочешь флаг приделай, чтобы инициализировать один раз..
а объект класса объявляй глобально (как форма объявляется TForm *Form1), и инклудь этот модуль где надо..
olegenty
Отправлено: 03.06.2004, 15:59


Ветеран

Группа: Модератор
Сообщений: 2412



я для хранения очень уж глобальных переменных, всего лишь написал бы компонент невизуальный (бонус — редактирование свойств в дизайн-тайм + возможность сохрания в реестр/ини любым компонентом, для этого предназначенным), дибо DataModule, насоздавал там свойств и методов, и работай... (я делал и то и другое, всё работает, оч. удобно)

не стоит усложнять себе жизнь... biggrin.gif
_vadim_
Отправлено: 03.06.2004, 17:08


Ученик-кочегар

Группа: Участник
Сообщений: 18



Ок, буду пробовать другие пути. smile.gif

to timson: Закрытый конструктор нужен чтобы был. Но как ты наверное заметил он не реализован, следовательно инициализация не возможна.

to All: Почему я хотел сделать, через статик, потому, что для такого класса не требуется наличие объекта этого класса. Вообще имхо очень удобно.

Но! Я все равно не понял, почему ругается именно линкер?!
И еще, я ведь не инициализирую переменную непосредственно. Ее инициализация происходит внутри класса при вызове функции-элемента ЭТОГО класса. Обьясните плиз, для тех кто на бронепоезде. sad.gif
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



Но с другой стороны конструкция не противоречит языку — так что дело принципа.

Вот и я про то-же smile.gif
А 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



Всем спасибо за участие.

Из ваших ответов и собственных попыток, я сделал вывод, что статик сам по себе вещь удобная во многих случаях. Но! в реализации борланда статиком лучше не пользоваться. sad.gif
Asher
Отправлено: 04.06.2004, 15:57


Мастер участка

Группа: Модератор
Сообщений: 550



Да нормальная реализация. Работает без проблем — главное правильно пользоваться. например ка timson писал smile.gif
От 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++ делал это за вас biggrin.gif
AVC
Отправлено: 04.06.2004, 16:55


Ветеран

Группа: Модератор
Сообщений: 1583



Опс

Отредактировано AVC — 04/06/2004, 17:00

Вернуться в Вопросы программирования в C++Builder