Статические члены
От: WirBi  
Дата: 03.11.04 11:43
Оценка:
Язык программирования C++ Бьерн Страуструп Специальное издание
10.2.4 Статические члены стр. 274

class Date {
   int d, m, y;
   static Date default_date;
public:
   Date (int dd=0, int mm=0, int yy=0);
   // ...
   static void set_default (int, int, int);
};


Цитата:
Статические члены — и функции и данные — должны быть где-то определены. Например:

Date Date::default_date (16, 12, 1770);

void Date::set_default (int d, int m, int y)
{
   Date::default_date = Date (d, m, y);
}


Так вот вопрос, где именно должны быть определены функции и данные? Как это правильно использовать? И где об этом подробно почитать?
Re: Статические члены
От: Libra Россия  
Дата: 03.11.04 11:58
Оценка:
Здравствуйте, WirBi, Вы писали:

Это значит что должен быть примерно вот такой код
//date_header.h file
#ifndef _DATE_HEADER_
#define _DATE_HEADER_

//это ОБЪЯВЛЕНИЕ класса и его членов
class Date {
   int d, m, y;
   static Date default_date;
public:
   Date (int dd=0, int mm=0, int yy=0);
   // ...
   static void set_default (int, int, int);
};
#endif


//date_implementtion.cpp file

#include "date_header.h"

//все что написано ниже это ОПРЕДЕЛЕНИЕ

Date Date::default_date (16, 12, 1770);

void Date::set_default (int d, int m, int y)
{
   Date::default_date = Date (d, m, y);
}
Species come and go, but the earth stands forever fast...
Re[2]: Статические члены
От: WirBi  
Дата: 03.11.04 12:32
Оценка:
Здравствуйте, Libra, Вы писали:

L>Это значит что должен быть примерно вот такой код


//date_implementtion.cpp file

#include "date_header.h"

//все что написано ниже это ОПРЕДЕЛЕНИЕ

Date Date::default_date (16, 12, 1770);

void Date::set_default (int d, int m, int y)
{
   Date::default_date = Date (d, m, y);
}


Но если я добавляю конструктор Date, как в книге, то:

//date_implementtion.cpp file

#include "date_header.h"

Date::Date (int dd, int mm, int yy)
{
   d = dd ? dd : default_date.d;
   m = mm ? mm : default_date.m;
   y = yy ? yy : default_date.y;
}

Date Date::default_date (16, 12, 1770);

void Date::set_default (int d, int m, int y)
{
   Date::default_date = Date (d, m, y);
}


У меня при компиляции ошибка `dafault_date' undeclared (first use this function) в конструкторе Date.
Re: Статические члены
От: LaptevVV Россия  
Дата: 03.11.04 12:33
Оценка: 5 (2)
Здравствуйте, WirBi, Вы писали:

WB>Так вот вопрос, где именно должны быть определены функции и данные? Как это правильно использовать? И где об этом подробно почитать?

Подробно — здесь
Ссылки [1-...] это стандарт С++

Глобальные (и статические, как локальные, так и нет) переменные компилятор размещает в статической памяти, и время жизни таких переменных совпадает с временем выполнении программы. В стандарте [1-3.6.2] указано, что такие переменные, в отличие от локальных (не статических) и динамических, неявно инициализируются по умолчанию, причем до начала выполнения функции main. Такая инициализация называется статической, в отличие от динамической, задаваемой программистом явно. Встроенные типы инициализируются нулями. Для объектов реализованных классов инициализация нулями обычно невозможна, поэтому для глобальных объектов не встроенных типов вызывается конструктор по умолчанию (без аргументов). Если в классе его нет, то возникает ошибка трансляции. Обратите внимание — вызывается именно конструктор без аргументов, а не конструктор инициализации. Последний применяется для явной инициализации.
В рамках одного модуля порядок инициализации переменных встроенных типов определяется порядком объявления. Конструкторы для создания и инициализации глобального объекта тоже вызываются в порядке объявлений объектов. Деструкторы вызываются перед завершением программы в обратном порядке.

Продолжаем.

Самое время вспомнить о статических элементах класса [1-9.4]. Вообще-то статическим элементом класса может быть как поле, так и метод. Естественно, статические методы предназначены, в первую очередь, для манипуляции статическими полями.
К статическим методам мы еще вернемся позднее, а сейчас займемся статическими полями и их инициализацией. Б. Страуструп [2, c.274] определяет статическое поле как поле, которое "является частью класса, но не является частью объекта этого класса". Это означает, что статические поля класса, как и все переменные, размещаемые в статической памяти, создаются в единственном экземпляре, независимо от количества определяемых в программе объектов. Все объекты (даже созданные динамически) разделяют единственную копию статических полей [1 9.4.2]. Более того, все наследники тоже разделяют эту единственную копию. При этом в класс включается только объявление, а определение статического поля выполняется отдельно, за пределами класса. Обычно определение включается в модуль с реализацией класса. Единственным исключением из этого правила являются целочисленные статические константы, которые разрешено определять непосредственно в классе.
Естественно, определение должно быть единственным в программе, иначе компоновщик (не компилятор) сообщит о повторном определении. Если определение отсутствует, то тоже получим ошибку компоновки.

При определении поля выполняется и его инициализация. Если статическое поле является константным, то инициализация обязательна. Инициализация статических полей выполняется точно так же, как и инициализация глобальных и статических переменных [1-9.4.2/7]. Для не константных полей элементарных типов при отсутствии явной инициализации выполняется обнуление. Для статических полей не элементарных типов, естественно, вызываются конструкторы: либо явным образом конструктор инициализации, либо, при отсутствии явной инициализации, конструктор по умолчанию.
Продемонстрируем все это на элементарном примере (листинг 6.13).

//Листинг 6.13. Статические поля
//--------------------------файл-Person.h
#ifndef PERSON                            // страж
#define PERSON
#include <string>
class Person                            // демонстрационный класс
{ std::string Fio;                         // неэлементарный тип
  int year; 
  public:
    Person()                            // конструктор по умолчанию
   : Fio("Lippman"), year(1953) {}
    Person(std::string fio, int y)         // конструктор инициализации
    { Fio = fio; year = y; }
    void print() const;                    // вывод полей на экран
};
#endif
//--------------------------файл-StaticField.h
#include "Person.h"
class StaticField
{    static const int m01 = 1;    // инициализированная константа
    static const int m02;        // неинициализированное константное поле
    static const double m03;        // константное поле не целого типа
    static int m04;                // неконстантное поле целого типа
    static double m05;        // неконстантное поле не целого типа
    static const Person p;    // константное поле неэлементарного типа
    static Person t;        // неконстантное поле неэлементарного типа
public:
    static void print();    // статический метод
}; 
//--------------------------файл-StaticField.cpp
#include <iostream>
using std::cout;                        
using std::endl;
#include "StaticField.h";
// определение статических полей
const int StaticField::m02 = 2;            // обязательная инициализация 
const double StaticField::m03 = 3.1;    // обязательная инициализация
int StaticField::m04;                    // инициализация по умолчанию (ноль)
double StaticField::m05;                // инициализация по умолчанию (ноль)
const Person StaticField::p("Kupaev", 1999);    // конструктор инициализации
Person StaticField::t;                     // конструктор по умолчанию
// определение статического метода
void StaticField::print()
{ cout << m01 << endl;
  cout << m02 << endl;
  cout << m03 << endl;
  cout << m04 << endl;
  cout << m05 << endl;
  p.print();
  t.print();
}
void Person::print() const                 // константный нестатический метод
{ cout << Fio <<',' << year << endl; }
//--------------------------файл-main.cpp
#include <iostream>
using namespace std;
#include "StaticField.h"
int main()
{    StaticField::print();                // вывод значений статических полей
    return 0;
}

В этой программе класс Person написан только для демонстрации статических полей не элементарного типа. В нем определено два конструктора: по умолчанию и инициализации, — чтобы продемонстрировать вызовы при инициализации статических полей типа Person.
В файле StaticField.h прописано определение класса StaticField, где объявляется ряд статических полей, константных и не константных. Для вывода значений на экран объявляется статический метод print(). Определение статических полей выполняется в файле реализации StaticField.cpp. Для константных статических полей (m02 и m03) инициализацию писать обязательно. Не константные статические поля элементарных типов (m04 и m05) инициализируются по умолчанию — выполняется обнуление, как для глобальных или статических переменных.
И наконец, определение статических полей типа Person демонстрирует вызов конструкторов. Поле p должно быть обязательно проинициализировано, так как является константным. Именно для его инициализации в классе Person реализован конструктор инициализации. Поле t не является константным, поэтому определяется без явной инициализации. Однако для него вызывается конструктор по умолчанию, что можно наблюдать при вызове статического метода print() в главной программе. Программа выведет на экран
1 // m01 – константа, инициализируется в классе
2 // m02 – константа, инициализируется явно
3.1 // m03 – константа, инициализируется явно
0 // m04 – не константа, инициализируется по умолчанию (0)
0 // m05 – не константа, инициализируется по умолчанию (0)
Kupaev,1999 // p — константа, инициализируется явно
Lippman,1953 // t — не константа, инициализируется неявно
Обратите внимание — статический метод работает, хотя не определено ни одного объекта типа StaticField. Именно поэтому вызов метода пишется с префиксом — именем класса
StaticField::print();

В отличие от этого метода, метод print() класса Person вызывается для конкретных объектов p и t.
Определения статических полей, на первый взгляд, противоречат всем принципам инкапсуляции: поля объявлены приватными, но значения им присваиваются "в открытую". Однако, во-первых, такая инициализация разрешена только в определении, которое обязан предоставить создатель класса, иначе программа не пройдет компоновку. Во-вторых, определение-то у нас единственное. Таким образом, механизм защиты данных работает по-прежнему — присвоить значение приватной статической переменной "в открытую" в другом месте не получится.

Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[3]: Статические члены
От: LaptevVV Россия  
Дата: 03.11.04 13:06
Оценка:
Здравствуйте, WirBi, Вы писали:

WB>У меня при компиляции ошибка `dafault_date' undeclared (first use this function) в конструкторе Date.

Вот этот пример работает. Правда, я делал все в одном файле.

class Date {
   int d, m, y;
   static Date default_date;
public:
   Date (int dd=0, int mm=0, int yy=0);
   // ...
   static void set_default (int, int, int);
   static void print()    
   { std::cout << Date::default_date.y <<'.' 
           << Date::default_date.m <<'.'
           << Date::default_date.d << std::endl; 
   } 
};

Date Date::default_date = Date(16, 12, 1770);
Date::Date (int dd, int mm, int yy)
{
    d = dd; 
    m = mm; 
    y = yy;
}

void Date::set_default (int dd, int mm, int yy)
{
    Date::default_date.d = dd; 
    Date::default_date.m = mm; 
    Date::default_date.y = yy;
}

int main()
{   Date::print();
}
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Статические члены
От: folk Россия  
Дата: 03.11.04 13:31
Оценка: +2
Libra:
Ошибки в терминах:
>
> Это значит что должен быть примерно вот такой код
>
> //date_header.h file
> #ifndef _DATE_HEADER_
> #define _DATE_HEADER_
> 
> //это ОБЪЯВЛЕНИЕ класса и его членов
// нет, это ОПРЕДЕЛЕНИЕ класса, объявление вот: class Date;
> class Date {
>    int d, m, y;
>    static Date default_date;
> public:
>    Date (int dd=0, int mm=0, int yy=0);
>    // ...
>    static void set_default (int, int, int);
> };
> #endif
>

>
>
> //date_implementtion.cpp file
> 
> #include "date_header.h"
> 
> //все что написано ниже это ОПРЕДЕЛЕНИЕ
// ОПРЕДЕЛЕНИЯ ЧЛЕНОВ КЛАССА
> 
> Date Date::default_date (16, 12, 1770);
> 
> void Date::set_default (int d, int m, int y)
> {
>    Date::default_date = Date (d, m, y);
> }
>
Posted via RSDN NNTP Server 1.9 gamma
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[3]: Статические члены
От: Libra Россия  
Дата: 04.11.04 06:44
Оценка:
Здравствуйте, folk, Вы писали:

F>Libra:

F>Ошибки в терминах:
>>
>> Это значит что должен быть примерно вот такой код
>>
>> //date_header.h file
>> #ifndef _DATE_HEADER_
>> #define _DATE_HEADER_
>> 
>> //это ОБЪЯВЛЕНИЕ класса и его членов
F>// нет, это ОПРЕДЕЛЕНИЕ класса, объявление вот: class Date;
>> class Date {
>>    int d, m, y;
>>    static Date default_date;
>> public:
>>    Date (int dd=0, int mm=0, int yy=0);
>>    // ...
>>    static void set_default (int, int, int);
>> };
>> #endif
>>

>>
>>
>> //date_implementtion.cpp file
>> 
>> #include "date_header.h"
>> 
>> //все что написано ниже это ОПРЕДЕЛЕНИЕ
F>// ОПРЕДЕЛЕНИЯ ЧЛЕНОВ КЛАССА
>> 
>> Date Date::default_date (16, 12, 1770);
>> 
>> void Date::set_default (int d, int m, int y)
>> {
>>    Date::default_date = Date (d, m, y);
>> }
>>


согласен...
прошу прощения за то что пытался ввести в заблуждение
Species come and go, but the earth stands forever fast...
Re: Статические члены
От: WirBi  
Дата: 10.11.04 08:41
Оценка:
Все разрешилось после смены компилятора.
... << RSDN@Home 1.1.3 stable >>
Re[2]: Статические члены
От: Lorenzo_LAMAS  
Дата: 10.11.04 08:49
Оценка: +1
WB>Все разрешилось после смены компилятора.

Я НЕ ВЕРЮ. Ты хочешь сказать, что старый компилятор не компилировал такое :

//date.h
class Date
{
public:
   Date(int d); //скипаю месяц и год

private:
   int d_;
   static Date defDate_;
   static void SetDef(int d);
};
//test.cpp
#include "date.h"

Date::Date(int d)
{
   d_ = d ? d : defDate_.d_;
}

Date Date::defDate_(1);

void Date::SetDef(int d)
{
   defDate_.d_ = d;
}

int main()
{
   Date d(0);
   return 0;
}


Что это за компилятор у тебя был тогда?
Of course, the code must be complete enough to compile and link.
Re[3]: Статические члены
От: WirBi  
Дата: 12.11.04 13:43
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Я НЕ ВЕРЮ. Ты хочешь сказать, что старый компилятор не компилировал такое :

Код приведенный тобой компилируется. Проблемы возникли в другом месте, когда я добавил конструктор как в книге, посмотри, я приводил код.

L_L>Что это за компилятор у тебя был тогда?

Dev C++ 4.9.8.9 MinGW (GCC) 3.2 (mingw special 20020817-1)
... << RSDN@Home 1.1.3 stable >>
Re[4]: Статические члены
От: Lorenzo_LAMAS  
Дата: 12.11.04 13:59
Оценка:
WB>Код приведенный тобой компилируется. Проблемы возникли в другом месте, когда я добавил конструктор как в книге, посмотри, я приводил код.

Мой код практически идентичен твоему, за исключением числа параметров конструктора. И за счет отсутствия избыточной квалификации имени в SetDef. Ну так в чем же дело?
Of course, the code must be complete enough to compile and link.
Re[5]: Статические члены
От: WirBi  
Дата: 15.11.04 08:13
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Мой код практически идентичен твоему, за исключением числа параметров конструктора. И за счет отсутствия избыточной квалификации имени в SetDef. Ну так в чем же дело?


Я делал тоже самое, но разбивал на файлы.
Другой компилятор я использую дома. Я проверил, в "домашнем" варианте я использовал расширение файлов ".hpp", а на работе ".h"
Я сейчас изменил расширение хедера, на работе, с ".h" на ".hpp", все остальное оставил так как было (конечно еще в .cpp изменил имя подключаемого файла), все скомпилировалось. Я не понимаю как это связано.
Дома компилятор GCC 3.4
... << RSDN@Home 1.1.3 stable >>
Re[6]: Статические члены
От: Lorenzo_LAMAS  
Дата: 15.11.04 08:23
Оценка:
WB>Я делал тоже самое, но разбивал на файлы.
WB>Другой компилятор я использую дома. Я проверил, в "домашнем" варианте я использовал расширение файлов ".hpp", а на работе ".h"
WB>Я сейчас изменил расширение хедера, на работе, с ".h" на ".hpp", все остальное оставил так как было (конечно еще в .cpp изменил имя подключаемого файла), все скомпилировалось. Я не понимаю как это связано.
WB>Дома компилятор GCC 3.4

.hpp или .h — роли не играет, главное, чтоб ты #include делал правильно. Если б проблема была с заголовком (его включением) дело вообще далеко не пошло бы — сказал бы, что не может включить и т.д.
Of course, the code must be complete enough to compile and link.
Re[7]: Статические члены
От: WirBi  
Дата: 15.11.04 11:18
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>.hpp или .h — роли не играет, главное, чтоб ты #include делал правильно. Если б проблема была с заголовком (его включением) дело вообще далеко не пошло бы — сказал бы, что не может включить и т.д.


Ты знаешь, видимо я идиот и руки у меня кривые... Нормально все работает. Я сейчас еще раз руками все набрал. Только не пойму в чем причина была (столько времени мучился) , но компилятор получается не виноват.
... << RSDN@Home 1.1.3 stable >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.