2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




 
 C++: static-атрибуты класса - почему так?
Сообщение01.12.2011, 16:10 
Давно пишу на плюсах, но как-то не приходилось пользоваться статическими атрибутами. Недавно же такая необходимость возникла. Недолго думая, написал код вида:
Код:
class C
{
  public:
    C();
    ~C();
  private:
    static string s;
};

на что VC++ выдал мне link error следующего содержания:
Код:
1>C.obj : error LNK2001: unresolved external symbol "private: static class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > C::s" (?s@C@@0V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A)

Заглянув в справочник Шилдта, обнаружил, что статический атрибут недостаточно объявить в описании класса и что правильно писать так:
Код:
class C
{
  public:
    C();
    ~C();
  private:
    static string s;
};

string C::s;

В таком варианте всё собирается успешно. Но я вот задался вопросом: а для чего это было сделано, зачем повторно объявлять атрибут, который уже был объявлен в описании класса? Может быть, это связано с какими-то ограничениями старых компиляторов? Знает ли кто-нибудь?

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение01.12.2011, 16:21 
Аватара пользователя
Начнем с того, что
Код:
string C::s;


не объявление, а определение...

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение01.12.2011, 16:33 
kiyanyn
ОК, согласен. Но ведь методы можно определять прямо в описании класса. Почему не разрешается делать это с атрибутами? Причём не со всеми, а именно со статическими?

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение01.12.2011, 17:42 
Аватара пользователя
aUruM в сообщении #510446 писал(а):
kiyanyn
ОК, согласен. Но ведь методы можно определять прямо в описании класса. Почему не разрешается делать это с атрибутами? Причём не со всеми, а именно со статическими?


Встречный вопрос - и как вы определите не статический член? Он создается только при создании объекта, до того его нет, так что это не определение, а объявление...

А что касается определения статического члена класса - то как, например, в общем случае разрешать конфликт имен?

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение01.12.2011, 17:48 
Статические данные класса по сути - глобальные переменные с видимостью в namespace класса. Соответственно, на них налагаются те же требования, что и на обычные глобальные переменные, в том числе определение только в одном модуле компиляции. Иначе трудно будет реализовать единственность и однократное конструирование такого объекта.

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение01.12.2011, 23:04 
Цитата:
Встречный вопрос - и как вы определите не статический член? Он создается только при создании объекта, до того его нет, так что это не определение, а объявление...

Согласен, про не-static атрибуты я сказал ерунду. Не подумал.
Цитата:
А что касается определения статического члена класса - то как, например, в общем случае разрешать конфликт имен?

Не очень понял, о каком конфликте имён идёт речь... Поясните, пожалуйста.
Цитата:
Статические данные класса по сути - глобальные переменные с видимостью в namespace класса. Соответственно, на них налагаются те же требования, что и на обычные глобальные переменные, в том числе определение только в одном модуле компиляции. Иначе трудно будет реализовать единственность и однократное конструирование такого объекта.

Что-то я не очень понимаю, как это соотносится с моим вопросом... Прошу прощения, если туплю. Можете подробнее объяснить? Суть моего вопроса такова: почему компилятору недостаточно строки
Код:
static string s;

в описании класса?

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение01.12.2011, 23:25 
Потому что компилятору надо ровно в одном объектном файле завести эту переменную с конструированием. Чтобы указать ему в каком именно файле это делать, вы пишете в одном из исходных файлов (не заголовке) определение этой переменной.

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение01.12.2011, 23:49 
venco
Хм, это объяснение выглядит логичным. Но почему же тогда допускается реализация методов в заголовке?

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение02.12.2011, 00:32 
aUruM в сообщении #510665 писал(а):
venco
Хм, это объяснение выглядит логичным. Но почему же тогда допускается реализация методов в заголовке?
Потому что inline методам не обязательно быть в одном экземпляре. Более того, часто этого метода в явном виде вообще нет в скомпилированной программе.

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение02.12.2011, 00:40 
venco
Ясно, спасибо за разъяснение!
Цитата:
Более того, часто этого метода в явном виде вообще нет в скомпилированной программе.

Не могли бы Вы рассказать подробнее про это, если не сложно, или дать ссылку? Интересно.

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение02.12.2011, 01:02 
При вызове inline функции (не только в классе) при возможности компилятор вставляет код этой функции прямо в вызывающий. Это позволяет лучше соптимизировать код, и избежать кода сопутствующего вызову функции - сохранение параметров и регистров в стек, собственно вызов, коррекция stackframe, и т.д.

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение02.12.2011, 01:07 
venco
Спасибо!

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение02.12.2011, 02:33 
2aUruM
Цитата:
Но я вот задался вопросом: а для чего это было сделано, зачем повторно объявлять атрибут, который уже был объявлен в описании класса?

Можно ещё совсем упрощенно объяснить -- выделение памяти под обычный элемент класса, например "поле" field в классе struct myclass {int field;};, происходит когда мы объявляем переменную-объект этого класса (e.g. myclass myobject;) или создаем этот объект оператором new.

Но если мы объявим field как static, т.е. напишем struct myclass {static int field;};, этот элемент должен быть доступен даже просто как myclass::field, причем вообще без необходимости создания объекта класса. Спрашивается, а где-же тогда выделяется память под такую переменную? Вот именно это лишнее определение static int myclass::field; вне класса и решает эту проблему.

Цитата:
Может быть, это связано с какими-то ограничениями старых компиляторов?

Хм, интересная мысль. Я слышал, что некоторые компиляторы действительно позволяют обходится единственным определением (с инициализацией) static-элемента в пределах определения класса. Наверное что-то вроде struct myclass {static const int field=2;};, но это не совсем по стандарту и при необходимости должно быть заменено тем же enum'ом. Как с этим дела обстоят в новом C++11 -- пока не знаю.

Кстати, коль скоро static-методы в отличии от static-данных не требуют дублирования описания, вместо таких переменных класса можно попробовать использовать методы. Например struct myclass {static int field(){return 2;}}; :)

Ok, необходимость повторного описания static-переменных выглядит как техническое ограничение. Но можно привести простой пример, демонстрирующий существенность такого поведения. Скажем, есть класс в заголовке. Он используется в другом сpp-файле. Как должен был бы действовать компилятор, чтобы обойтись одним определением static-переменной в самом классе? Трудно сказать. Ведь этот заголовок может использоваться многими файлами, и, неявно, память должна была бы выделяться либо в одном из них (в каком?), либо в каждом из них, что в свою очередь, очевидно, может нарушить требование единственности static-переменной и одинаковости её значения для всех объектов класса и без использования оных.

 
 
 
 Re: C++: static-атрибуты класса - почему так?
Сообщение02.12.2011, 10:08 
Аватара пользователя
В принципе, чисто теоретически можно пойти и на такое :), но разрешение конфликта будет ужасным...

Например:

s.h:
Код:
class Test
{
public:
    static char * s;
};


s1.cpp:
Код:
#include "s.h"
char * Test::s = __FILE__;


s2.cpp:
Код:
#include "s.h"
char * Test::s = __FILE__;


s3.cpp:
Код:
#include "s.h"
#include <stdio.h>
int main()
{
    printf("%s\n",Test::s);
}


Компилируем, получаем предупреждение о redefinition... Программа работает, но этого ли мы хотели? :-)

Вот примерно то же получится и в случае определения статического члена в объявлении класса...

 
 
 [ Сообщений: 14 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group