nikedeforest
|
|
« : 13-09-2005 11:59 » |
|
Пробовал так class base{ private: const double a=2.0; };
Но ясно дело так нельзя. А как тогда можно? зы: Идея пришла, попробовать как со статическими переменными, сейчас проверю.
|
|
|
Записан
|
ещё один вопрос ...
|
|
|
ChaoticCube
ChaoticCube
Помогающий
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
|
|
« Ответ #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
Помогающий
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
|
|
« Ответ #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
Нет не пробовал. Сейчас попробую.
|
|
|
Записан
|
ещё один вопрос ...
|
|
|
Михалыч
|
|
« Ответ #5 : 13-09-2005 14:50 » |
|
А почему бы и не так? (А пуркуа бы и не па ) class base{ base(): a(2.0) {}; private: const double a; }; Как и предлагал ChaoticCube - список инициализаторов. Должно стрелять по определению...
|
|
« Последнее редактирование: 13-09-2005 14:56 от Михалыч »
|
Записан
|
Поживем - увидим... Доживем - узнаем... Выживу - учту
|
|
|
Finch
Спокойный
Администратор
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?
|
|
|
Записан
|
|
|
|
Михалыч
|
|
« Ответ #9 : 14-09-2005 01:18 » |
|
Должно, и наверняка будет. Но не па по двум причинам. Плюс к этому не нравятся мне подобные нестатические "константы" - чтобы узнать ее значение, нужно создать экземпляр класса. А логично ли требовать непременно создавать окружность, чтобы узнать значение числа pi?
Это, конечно да. Применение констант в таком виде дело вкуса, и на мой взгляд - спорное. Нравится-не нравится... Вопрос-то был по возможности ввести константу в класс nikedeforest Скажи, а зачем тебе это нужно, не легче ли дефайны определить перед класом?
#define - это не есть чистый и "правоверный" С++ путь Чревато иногда, понимашь...
|
|
|
Записан
|
Поживем - увидим... Доживем - узнаем... Выживу - учту
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #10 : 14-09-2005 04:38 » |
|
если надо целые константы, я делаю так: class base{ private: enum { a=2, b=3 }; }; а дробные можно получить делением целых кроме ток, значения енумок показыватся под дебагом как для переменных
|
|
« Последнее редактирование: 14-09-2005 04:40 от Алексей1153 »
|
Записан
|
|
|
|
Hooter
|
|
« Ответ #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
|
|
« Ответ #13 : 14-09-2005 12:00 » |
|
Всем спасибо большое. Использовал способ предложенный Михалычем (писал программу до поста Альфа и подумал, что так предпочтительней). nikedeforest Скажи, а зачем тебе это нужно, не легче ли дефайны определить перед класом?
У Шилдта я читал, что желательно по возможности воздерживаться от дефайнов, да и не нравились они мне никогда.
|
|
|
Записан
|
ещё один вопрос ...
|
|
|
Михалыч
|
|
« Ответ #14 : 14-09-2005 13:10 » |
|
Ага, я не помню, правда, где - но про такой трюк с enum-ами читал. Там говорилось, что это способ "обойти" компиляторы, не позволяющие присваивание или инициализацию констант в классе. Какие-то поддерживают, какие-то нет... GCC - точно, без проблем. И, кажется, борланд какой-то тоже. Но не уверен
|
|
|
Записан
|
Поживем - увидим... Доживем - узнаем... Выживу - учту
|
|
|
Hooter
|
|
« Ответ #15 : 14-09-2005 13:22 » |
|
Вот этот трюк Алексей1153 уже написал Такая штука называется enum hack. если надо целые константы, я делаю так:
class base{ private:
enum { a=2, b=3 };
};
|
|
|
Записан
|
|
|
|
Hooter
|
|
« Ответ #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-функции не имеют адреса в памяти, но из этого вовсе не следует, что их тело не определено. Конструкция это просто современная замена устаревшему стилю C О каком адресе в данном случае может идти речь?
|
|
|
Записан
|
|
|
|
Hooter
|
|
« Ответ #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). Поставленный вопрос про функции некорректен, поскольку функция не является объектами в терминологии стандарта. О каком адресе в данном случае может идти речь? Первоначально разговор шел о другом
|
|
|
Записан
|
|
|
|
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 » |
|
Теперь понятно. Немного эта игра слов с толку сбила. Похоже, в данном документе определение - синоним инстанцирования. Отсюда и неестественное с точки зрения семантики требование к константе иметь адрес.
Впрочем, пожалуй, иначе они и не выкрутились бы из ловушки, в которую сами себя загнали, сделав исключение для инициализации целых типов. Потянешь за эту ниточку - весь стандарт рассыпется.
|
|
|
Записан
|
|
|
|
|