Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Как работать со статическими членами класса?  (Прочитано 19020 раз)
0 Пользователей и 9 Гостей смотрят эту тему.
Fractaler
Гость
« : 27-04-2007 11:59 » 

Всем доброго времени суток!
Помогите чайнику, запарился совсем. Нужна переменная (вообще-то массив, но мне бы с переменной разобраться) который будет для всех объектов данного класса одинаковым. Если я правильно понял, это и есть должен быть статический член класса.
Пишу так:
Код:
#include <iostream>
#include <cstdlib>

using namespace std;

class figure
{
  private:
    static int i;
  public:
    figure::figure(int a) {i=a;}
    const int getI() {return i;}
};

int main(int argc, char *argv[])
{
           figure a(1), b(2);

           cout << "Для объекта а: " << a.getI() << "\n";
           cout << "Для объекта b: " << b.getI() << "\n";

  return EXIT_SUCCESS;
}
Получаю
Цитата
$ g++ temp.cpp -o tmp
/tmp/ccEa8hsr.o(.gnu.linkonce.t._ZN6figure4getIEv+0x4): In function `figure::getI()':
: undefined reference to `figure::i'
/tmp/ccEa8hsr.o(.gnu.linkonce.t._ZN6figureC1Ei+0x7): In function `figure::figure(int)':
: undefined reference to `figure::i'
collect2: ld returned 1 exit status
Что я делаю не так?
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #1 : 27-04-2007 12:53 » 

Код:
figure::figure(int a) {i=a;}
Это по мелочам, зачем внутри класса так определять конструктор? Интересно, как у тебя пропустил такое компилятор?

Теперь по сушеству вопроса. Для статических переменных в классе нужно отдельно добавить переменную вне класса. Насколько я помню в описании было сказано, что статическая переменная внутри класса объявляется как extended, и в дальнейшем нужно ее слинковать.
Т.е. твой код будет выглядеть так
Код:
#include <iostream>
#include <cstdlib>

using namespace std;

class figure
{
   private:
    static int i;
   public:
    figure(int a) {i=a;}
    int getI() {return i;}
};

int figure::i=0;

int main(int argc, char *argv[])
{
           figure a(1), b(2);

           cout << "Для объекта а: " << a.getI() << "\n";
           cout << "Для объекта b: " << b.getI() << "\n";

  return EXIT_SUCCESS;
}
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Fractaler
Гость
« Ответ #2 : 27-04-2007 13:08 » 

Спасибо, помогло Улыбаюсь
Странно, вроде, раньше так делал, а не работало... Внимательней надо быть...

Что до мелочей, то конструктор будет выглядеть не так, просто я никак не мог понять, как использовать статическую переменную в функциях-членах класса.
Кстати, а почему компилятор мог не пропустить такой конструктор? Неужели статические переменные настолько отличаются?
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #3 : 27-04-2007 13:13 » 

Я сразу запустил твой код, не посмотрев синтаксис. Компилятор выдал мне сразу такую ошибку
Цитата
Main.cpp:11: error: extra qualification ‘figure::’ on member ‘figure’
Это не ошибка из-за статических методов, а ошибка двойного переопределения Улыбаюсь
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Fractaler
Гость
« Ответ #4 : 27-04-2007 13:20 » 

Опа! Теперь я точно ничего не понимаю..
У меня есть закрытая переменная i и к ней я обращаюсь из конструктора, присваивая ей значение параметра, который передан в конструктор. В чем тут переопределение?

P.S. До офтопа я еще не докатился?
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #5 : 27-04-2007 13:27 » 

Цитата
class figure
{
  private:
    static int i;
  public:
    figure::figure(int a) {i=a;}
    const int getI() {return i;}
};
Ты находишся уже внутри секции figure, и говориш компилятору, чтобы он нырял еше дальше, для опредения конструктора. Но на самом деле, такой секции внутри секции figure не сушествует. Отсюда и ошибка.

P.S. Я выделил жирным тот участок кода, на который у меня отругался компилятор Улыбаюсь
« Последнее редактирование: 27-04-2007 13:30 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Fractaler
Гость
« Ответ #6 : 27-04-2007 13:32 » 

А так правильно или это тоже самое?
Код:
class figure
{
  private:
    static int i;
  public:
    figure(int a);
    const int getI() {return i;}
};
figure::figure(int a)  {i=a;}
или как тогда? А черт его знает... Не может быть...
« Последнее редактирование: 27-04-2007 13:34 от Fractaler » Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #7 : 27-04-2007 13:37 » 

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

Записан

Не будите спашяго дракона.
             Джаффар (Коша)
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 27-04-2007 13:51 » 

Правильно. Кстати, умные люди советуют использовать инициализацию в таких случаях
Код:
figure::figure(int a):i(a)
{
;
}
« Последнее редактирование: 27-04-2007 13:53 от nikedeforest » Записан

ещё один вопрос ...
Fractaler
Гость
« Ответ #9 : 27-04-2007 14:11 » 

А, с конструктором понял, действительно странно, как сразу не заметил. Спасибо.
2 nikedeforest
Такую конструкцию в первый раз вижу, Это что? Ссылочку можно, где почитать? Или вкраце расскажи, пожалуйста.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #10 : 27-04-2007 14:25 » 

Вот выдержка из книжки Джефф Элджер "Библиотека программиста С++"
Цитата
Списки инициализации членов

Чтобы избавиться от этой проблемы, в C++ находится очередное применение символу : — для
создания списков инициализации членов. Так называется список спецификаций конструкторов,
разделенных занятыми и расположенных между сигнатурой конструктора и его телом.
      class Foo {
      public:
           Foo(char*);
      };
      class Bar : public Foo {
      public:
           Bar(char*);
      };
      class BarBar {
      private:
           Foo f;
           int x;
      public:
           BarBar();
      };
      Bar::Bar(char* s) : Foo(s) {...}
      BarBar::BarBar : f(“Hello”), x(17) {...}
В конструкторе Bar список инициализации членов используется для инициализации базового класса
Foo. Компилятор выбирает используемый конструктор на основании сигнатуры, определяемой по
фактическим аргументам. При отсутствии списка инициализации членов сконструировать Bar было бы
невозможно, поскольку компилятор не мог бы определить, какое значение должно передаваться
конструктору базового класса Foo. В конструкторе BarBar список инициализации членов
использовался для инициализации (то есть вызова конструкторов) переменных f и х. В следующем
варианте конструктор работает не столь эффективно (если только компилятор не отличается
сверхъестественным интеллектом):
      BarBar::BarBar() : f(“Hello”)
      {
           x = 17;
      }
                                                                                              35
Во втором варианте переменная х сначала инициализируется значением 0 (стандартное требование
C++) с использованием по умолчанию конструктора int без аргументов, а затем в теле конструктора
ей присваивается значение 17. В первом варианте имеется всего одна инициализация и потому
экономится один-два машинных такта. В данном примере это несущественно, поскольку переменная
х — целая, но если бы она относилась к более сложному классу с конструктором без аргументов и
перегруженным оператором присваивания, то разница была бы вполне ощутима.
Списки инициализации членов нужны там, где у базового класса или переменной нет конструктора без
аргументов (точнее, есть один и более конструктор с аргументами, но нет ни одного определенного
пользователем конструктора без аргументов). Списки инициализации членов не обязательны в тех
ситуациях, когда все базовые классы и переменные класса либо не имеют конструкторов, либо имеют
пользовательский конструктор без аргументов.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 27-04-2007 14:41 » 

Рихтер умный мужик Улыбаюсь. ИМХО, со списками инициализации сложно прогадать, о чем сказал и Рихтер. Хотя может есть другие мнения.
Записан

ещё один вопрос ...
Fractaler
Гость
« Ответ #12 : 27-04-2007 14:52 » 

Всё понятно Улыбаюсь
БоОоольшууущее спасибо!
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #13 : 28-04-2007 07:11 » 

Код:
class figure
{
  int i;
public:
  figure(int c):i(c){}
}

Хотя обычно я даже мелкие конструкторы вытаскиваю в cpp чтобы связанные с хедером файлы лишний раз не пересобирались при измении внутренностей конструктора, так под настроение Улыбаюсь

Все идём дружно идём курить стандарт С++ Улыбаюсь

Кстати статики и глобалы это зло Улыбаюсь
Записан

Странно всё это....
Vlaor
Гость
« Ответ #14 : 28-04-2007 12:19 » new

Код:
figure::figure(int a):i(a)
{
;
}
А вопрос по ходу. Пустой оператор в конструкторе это для эстетики или есть какой-то сакральный смысл? Улыбаюсь
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines