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

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

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

« : 13-09-2005 11:59 » 

Пробовал так
Код:
class base{
private:
const
      double a=2.0;
};

Но ясно дело так нельзя. А как тогда можно?
зы: Идея пришла, попробовать как со статическими переменными, сейчас проверю.
Записан

ещё один вопрос ...
ChaoticCube
ChaoticCube
Помогающий

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


« Ответ #1 : 13-09-2005 12:00 » 

class base{
private:
   static double a;
};

static base::a = 2.0

Вроде прокатывает. Но это не совсем константа
« Последнее редактирование: 13-09-2005 12:02 от ChaoticCube » Записан

Сила ночи, сила дня - одинакого фигня....
nikedeforest
Команда клуба

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

« Ответ #2 : 13-09-2005 12:09 » 

Блин, не выходит, вот что пишет
Цитата
e:\lab1\lab1\class_mat_mod.h(9) : error C2758: 'k' : must be initialized in constructor base/member initializer list
e:\lab1\lab1\class_mat_mod.h(3) : see declaration of 'k'
В конструкторе пробовал, тоже не получается.
Меня смущает вот это
Цитата
initializer list
Подсобите пожалуйста советом.
« Последнее редактирование: 20-12-2007 17:06 от Алексей1153++ » Записан

ещё один вопрос ...
ChaoticCube
ChaoticCube
Помогающий

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


« Ответ #3 : 13-09-2005 12:16 » 

initializer list - следующая штука:

 в конструкторе

 ClassA::ClassA
 : m_bA(false),
   m_bB(false), и т.д..

Но с константой легче от этого вроде как не становится....

А вот так ты пробовал?

class base{
private:
   static const double a;
};

static const base::a = 2.0

Записан

Сила ночи, сила дня - одинакого фигня....
nikedeforest
Команда клуба

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

« Ответ #4 : 13-09-2005 12:38 » 

Цитата
initializer list - следующая штука:

в конструкторе

ClassA::ClassA
: m_bA(false),
   m_bB(false), и т.д..

Но с константой легче от этого вроде как не становится....
Понял.
Цитата
А вот так ты пробовал?

class base{
private:
   static const double a;
};

static const base::a = 2.0
Нет не пробовал. Сейчас попробую.
Записан

ещё один вопрос ...
Михалыч
Команда клуба

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

« Ответ #5 : 13-09-2005 14:50 » 

А почему бы и не так? (А пуркуа бы и не па Улыбаюсь )
class base{
base(): a(2.0) {};
private:
const   double a;
};
Как и предлагал  ChaoticCube - список инициализаторов.
Должно стрелять по определению...
« Последнее редактирование: 13-09-2005 14:56 от Михалыч » Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
Finch
Спокойный
Администратор

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


« Ответ #6 : 13-09-2005 21:14 » 

nikedeforest Скажи, а зачем тебе это нужно, не легче ли дефайны определить перед класом?
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Alf
Гость
« Ответ #7 : 13-09-2005 21:20 » 

Небольшой набросок на тему, как можно и как нельзя объявлять константы в классе:

Код:
#include <stdio.h>

class ConstClass
{
public:
  static const int N; // только объявили, определим позднее
  static const int K = 5; // объявили и определили в одном флаконе
  // так можно 
  static const double pi;
  static const double e;
  // а вот так нельза - ошибка компиляции
  //  error C2864: 'e' : only const static integral data members
  //  can be initialized inside a class or struct
  //static const double e = 2.718281828459045;
};

// определяем все константы, которые не удалось определить в теле класса
const int ConstClass::N = 3;
const double ConstClass::pi = 3.1415927;
const double ConstClass::e = 2.718281828459045;

int main(int argc, char* argv[])
{
  printf("N = %10d\nK = %10d\npi = %10.8f\ne = %10.8f\n",
    ConstClass::N, ConstClass::K, ConstClass::pi, ConstClass::e);
return 0;
}

Небольшие комментарии:

Первая константа (int N) объявлена и затем определена вне класса. Такой подход универсален.

Вторая константа (int K) объявлена и определена внутри тела класса. По причине, мне непонятной, это работает только для интегральных типов; попытки определить внутри класса константы других типов давятся на корню (чудны дела твои, Страуструп...).

Третья и четвертая константы (double pi, e) объявлены внутри класса, а затем определены вне его, подобно первой. Это единственный известный мне способ объявления неинтегральной константы.

Попытка определить константу (double e) внутри класса приводит к ошибке компиляции (см. комментарии в коде).

Напоследок цитата из Страуструпа:
Цитата
Можно проинициализировать член, являющийся статической константой интегрального типа, добавив к объявлению члена константное выражение в качестве инициализирующего значения.

(Бьерн Страуструп, "Язык программирования C++. Специальное издание." - М:"Бином", 2001, п. 10.4.6.2. Члены-константы.)

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

P.S. Данный пример скомпилирован и выполнен в среде Visual Studio.NET. Попытка выполнить его в VC++ 6.0 не увенчалась успехом, он отказался воспринимать определение константы внутри класса. Обратите на это внимание. Возможно, это регулируется какими-то опциями, я не искал, ибо не было желания копать архаичный компилятор вглубь.

« Последнее редактирование: 20-12-2007 17:10 от Алексей1153++ » Записан
Alf
Гость
« Ответ #8 : 13-09-2005 21:37 » 

А почему бы и не так? (А пуркуа бы и не па Улыбаюсь )
class base{
base(): a(2.0) {};
private:
const   double a;
};
Как и предлагал ChaoticCube - список инициализаторов.
Должно стрелять по определению...

Должно, и наверняка будет. Но не па по двум причинам.

1. Экземпляр константы будет присутствовать в каждом экземпляре класса. А если у нас несколько десятков констант, а экземпляры класса создаются миллионами, и в каждом всего по нескольку байт полезных данных? При таком подходе мы просто забиваем оперативную память всяким мусором, используя ее с очень низким КПД. Конечно, нынче цены на оперативную память невысоки, и забить ее не так просто. Но все-таки...

2. Указывая, что некоторое значение является константным, мы тем самым даем компилятору простор для оптимизации. Например, зная, что a == 2.0 при любых условиях, компилятор может подставлять значение константы прямо в код вместо обращения к ячейке памяти, содержащей значение. Предложенный подход требует от компилятора куда больше интеллекта, чтобы выполнить такую оптимизацию. Кроме того, если у класса несколько конструкторов, необходимо не забыть в каждом из них инициализировать a. Оно нам надо? Да и нет гарантии, что все конструкторы определят a одинаково. А тогда и вовсе будет пикантная ситуация - неконстантная константа, значение которой для разных экземпляров разное. Поди-ка отладь такую прелесть...

Плюс к этому не нравятся мне подобные нестатические "константы" - чтобы узнать ее значение, нужно создать экземпляр класса. А логично ли требовать непременно создавать окружность, чтобы узнать значение числа pi?
Записан
Михалыч
Команда клуба

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

« Ответ #9 : 14-09-2005 01:18 » 

Должно, и наверняка будет. Но не па по двум причинам.
Плюс к этому не нравятся мне подобные нестатические "константы" - чтобы узнать ее значение, нужно создать экземпляр класса. А логично ли требовать непременно создавать окружность, чтобы узнать значение числа pi?
Это, конечно да. Применение констант в таком виде дело вкуса, и на мой взгляд - спорное.
Нравится-не нравится... Вопрос-то был по возможности ввести константу в класс Улыбаюсь
nikedeforest Скажи, а зачем тебе это нужно, не легче ли дефайны определить перед класом?
#define - это не есть чистый и "правоверный" С++ путь Улыбаюсь Улыбаюсь Улыбаюсь Чревато иногда, понимашь...
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #10 : 14-09-2005 04:38 » 

если надо целые константы, я делаю так:

class base{
private:

enum
{
   a=2,
   b=3
};

};

а дробные можно получить делением целых Ага

кроме ток, значения енумок показыватся под дебагом как для переменных Улыбаюсь
« Последнее редактирование: 14-09-2005 04:40 от Алексей1153 » Записан

Hooter
Опытный

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

« Ответ #11 : 14-09-2005 04:42 » 

Код:
#include <stdio.h>

class ConstClass
{
public:
...
  // а вот так нельза - ошибка компиляции
  //  error C2864: 'e' : only const static integral data members
  //  can be initialized inside a class or struct

  static const double e = 2.718281828459045;
};

...

int main(int argc, char* argv[])
{
  printf("N = %10d\nK = %10d\npi = %10.8f\ne = %10.8f\n",
    ConstClass::N, ConstClass::K, ConstClass::pi, ConstClass::e);
return 0;
}

Интересно, что gcc откомпилировал такое объявление-определение.
А что по этому поводу стандарт говорит?
« Последнее редактирование: 20-12-2007 17:12 от Алексей1153++ » Записан
Alf
Гость
« Ответ #12 : 14-09-2005 11:41 » 

Что говорит стандарт, не смотрел еще. А вот Страус, который сам себе стандарт, говорит, что так нельзя (см. цитату выше). Хотя непонятно, почему.
Записан
nikedeforest
Команда клуба

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

« Ответ #13 : 14-09-2005 12:00 » 

Всем спасибо большое. Использовал способ предложенный Михалычем (писал программу до поста Альфа и подумал, что так предпочтительней).
Цитата
nikedeforest Скажи, а зачем тебе это нужно, не легче ли дефайны определить перед класом?
У Шилдта я читал, что желательно по возможности воздерживаться от дефайнов, да и не нравились они мне никогда.
Записан

ещё один вопрос ...
Михалыч
Команда клуба

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

« Ответ #14 : 14-09-2005 13:10 » 

Ага, я не помню, правда, где - но про такой трюк с enum-ами читал.
Там говорилось, что это способ "обойти" компиляторы, не позволяющие присваивание или инициализацию
констант в классе.
Какие-то поддерживают, какие-то нет... GCC - точно, без проблем. И, кажется, борланд какой-то тоже.
Но не уверен Улыбаюсь
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
Hooter
Опытный

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

« Ответ #15 : 14-09-2005 13:22 » 

Вот этот трюк Улыбаюсь Алексей1153 уже написал
Такая штука называется enum hack.
если надо целые константы, я делаю так:

class base{
private:

enum
{
   a=2,
   b=3
};

};
Записан
Hooter
Опытный

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

« Ответ #16 : 14-09-2005 13:25 » 

Что говорит стандарт, не смотрел еще. А вот Страус, который сам себе стандарт, говорит, что так нельзя (см. цитату выше). Хотя непонятно, почему.
Залез в ISO/IEC 14882:1998 "Programming languages - C++".
В разделе declarations нигде явно не запрещается инициализировать double.
Хотя в примерах используются только int и bool.
Может в других разделах... но я их еще не смотрел внимательно.
Записан
NetRaider
Гость
« Ответ #17 : 17-09-2005 02:39 » 

Вторая константа (int K) объявлена и определена внутри тела класса.
Это не определнение, 'К' только объявлена, но не определена.

« Последнее редактирование: 20-12-2007 17:15 от Алексей1153++ » Записан
NetRaider
Гость
« Ответ #18 : 17-09-2005 02:40 » 

Что говорит стандарт, не смотрел еще. А вот Страус, который сам себе стандарт, говорит, что так нельзя (см. цитату выше). Хотя непонятно, почему.
Залез в ISO/IEC 14882:1998 "Programming languages - C++".
В разделе declarations нигде явно не запрещается инициализировать double.
Хотя в примерах используются только int и bool.
Может в других разделах... но я их еще не смотрел внимательно.
Смотри 9.4.2
Записан
Alf
Гость
« Ответ #19 : 18-09-2005 20:28 » 

Вторая константа (int K) объявлена и определена внутри тела класса.
Это не определнение, 'К' только объявлена, но не определена.

Что в таком случае следует добавить для определения K?
« Последнее редактирование: 20-12-2007 17:18 от Алексей1153++ » Записан
NetRaider
Гость
« Ответ #20 : 19-09-2005 00:03 » 

Что в таком случае следует добавить для определения K?

Определение ноебходимо, если необходимо использование адреса K. В других случаях можно не определять. Например:
Код:

template<int a>
struct B{};

class A
{
    static const int K = 5;
    int arr[K]; // определение не обязательно
    typedef B<K> R;  // определение не обязательно

};


Записан
Alf
Гость
« Ответ #21 : 19-09-2005 07:41 » 

Определение ноебходимо, если необходимо использование адреса K.

Определение необходимо, чтобы компилятор знал значение объекта и мог его использовать (в отличие от объявления, которое сообщает лишь тип объекта). Определение вовсе не означает, что объект будет распределен в памяти. Например, inline-функции не имеют адреса в памяти, но из этого вовсе не следует, что их тело не определено.

Конструкция

Код:
static const int K = 5;

это просто современная замена устаревшему стилю C

Код:
#define K 5

О каком адресе в данном случае может идти речь?
Записан
Hooter
Опытный

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

« Ответ #22 : 19-09-2005 08:12 » 

Залез в ISO/IEC 14882:1998 "Programming languages - C++".
В разделе declarations нигде явно не запрещается инициализировать double.
Смотри 9.4.2
Да, в этом разделе разрешается инициализировать интегральные типы. Но инициализировать double или float по-прежнему никто не запрещает.
Видимо, стандарт отдает решение этого вопроса производителям компиляторов.
Записан
NetRaider
Гость
« Ответ #23 : 20-09-2005 02:47 » 


Определение необходимо, чтобы компилятор знал значение объекта и мог его использовать (в отличие от объявления, которое сообщает лишь тип объекта). Определение вовсе не означает, что объект будет распределен в памяти. Например, inline-функции не имеют адреса в памяти, но из этого вовсе не следует, что их тело не определено.
От того содержит или нет объявление инициализатор, определением оно не становится (9.4.2/4).
Поставленный вопрос про функции некорректен, поскольку функция не является объектами в терминологии стандарта.

Цитата

Код:
#define K 5

О каком адресе в данном случае может идти речь?
Первоначально разговор шел о другом
Записан
NetRaider
Гость
« Ответ #24 : 20-09-2005 02:55 » 

Что в таком случае следует добавить для определения K?
const int ConstClass::K;
Записан
Alf
Гость
« Ответ #25 : 20-09-2005 07:05 » 

От того содержит или нет объявление инициализатор, определением оно не становится (9.4.2/4).

Раз уж приведена ссылка на стандарт, да еще и с указанием конкретного пункта, грех не почитать. Смотрим:

Цитата
If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (expr.const). In that case, the member can appear in integral constant expressions within its scope. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.

(выделение мое).
 
Поставленный вопрос про функции некорректен, поскольку функция не является объектами в терминологии стандарта.

Вопрос насчет константы ничуть не корректнее, поскольку она также может быть предметом inline-подстановки (имеется в виду именно константа, а не объект, значение которого не может быть изменено). Тем более если уж если зашла речь об адресе константы (правда, непонятно, зачем), то и функция имеет адрес, ибо можно использовать указатель на нее. Принципиальной разницы не вижу.

P.S. Не увидел в стандарте при беглом просмотре, что есть "объекты в его терминологии". Вопрос к знатокам, кто в нем бегло ориентируется: в каком пункте искать это определение?
Записан
NetRaider
Гость
« Ответ #26 : 20-09-2005 07:48 » 

Раз уж приведена ссылка на стандарт, да еще и с указанием конкретного пункта, грех не почитать. Смотрим:

Цитата
The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.

Выделение мое.
Что есть used ? Идем в 3.2/2 -
Цитата
An object or nonoverloaded function is used if its name appears in a potentiallyevaluated
expression.

Potentially-evaluated expression.
Цитата
An expression is potentially evaluated unless either it is the operand of the sizeof operator (5.3.3), or it is
the operand of the typeid operator and does not designate an lvalue of polymorphic class type (5.2.8) .
По поводу этого пункта есть Defect Report 48
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#TC1 Status

Цитата
...
Proposed Resolution: Change the first sentence of 3.2 
...
to
An expression is potentially evaluated unless it appears where an integral constant expression is required (see 5.19  expr.const ), is the operand of the sizeof operator (5.3.3  expr.sizeof ), or is the operand of the typeid operator and the expression does not designate an lvalue of polymorphic class type (5.2.8  expr.typeid ).

Исходя из этого - определение требуется если возникнет необходимость в вычислении адреса константы, а в примерах приведенных мной выше - не требуется.

Цитата

 Не увидел в стандарте при беглом просмотре, что есть "объекты в его терминологии". Вопрос к знатокам, кто в нем бегло ориентируется: в каком пункте искать это определение?
Цитата

1.8:
The constructs in a C++ program create, destroy, refer to, access, and manipulate objects. An object is a
region of storage. [Note: A function is not an object, regardless of whether or not it occupies storage in the
way that objects do. ...
Записан
NetRaider
Гость
« Ответ #27 : 20-09-2005 08:24 » 

Тем более если уж если зашла речь об адресе константы (правда, непонятно, зачем)

Затем, чтобы показать что это(см.ниже) не является определением k
Код:
struct A
{
    static const int k = 10;
};

void foo(const int* a)
{
    *a+1;
}

int main()
{
   foo(&A::k); // linker error
}
Записан
Alf
Гость
« Ответ #28 : 20-09-2005 09:57 » 

Теперь понятно. Немного эта игра слов с толку сбила. Похоже, в данном документе определение - синоним инстанцирования. Отсюда и неестественное с точки зрения семантики требование к константе иметь адрес.

Впрочем, пожалуй, иначе они и не выкрутились бы из ловушки, в которую сами себя загнали, сделав исключение для инициализации целых типов. Потянешь за эту ниточку - весь стандарт рассыпется.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines