Показаны сообщения с ярлыком const. Показать все сообщения
Показаны сообщения с ярлыком const. Показать все сообщения

пятница, 8 апреля 2011 г.

четверг, 24 марта 2011 г.

51. Влияет ли наличие целочисленных констант-полей на размер класса?

Конечно, ведь каждый объект будет хранить свою константу. Но если константа static, то она будет храниться в одном экземпляре для всех объектов класса, и не повлияет на размер объекта.

пятница, 18 февраля 2011 г.

43. Каким образом разрешается инициализировать константные поля в классе?

Я уже насписал в ответе на "42. Как объявить константу в классе? Можно ли объявить дробную константу?". Вкратце:
class A{
  const T i;
  static const T i1 = 1; /* Если T - неинтегральный тип, может не сработать */ 
  static const T i2;  /* Для неинтегральных типов здесь только объявить, а проинициализировать позже */
  A():i(const_value){}
};

const T A::i2 = const_value;

К интегральным типам относятся char, short, int и long.

Есть еще один способ создания констант в классе, это enum hack. Изменим пример из ответа на 42-й вопрос.
class Year {
  /*...*/
  enum {MIN_YEAR = 1900, MAX_YEAR = 2100};
  /*...*/
}

четверг, 17 февраля 2011 г.

42. Как объявить константу в классе? Можно ли объявить дробную константу?

Сначала нужно подумать, что может означать "константа в классе". Попробую использовать относительно реальные примеры, а не мой любимый "class A" :)

Первый случай

Допустим, мы пишем класс Polygon (многоугольник). Мы хотим, чтобы количество вершин задавалось при создании объекта.
class Polygon{
  int vertexes;
public:
  Polygon(int v):vertexes(v){}
}
Таким образом, при создании экземпляра будет необходимо задать количество вершин, так как конструктора по умолчанию уже нет. Все хорошо, но в какой-нибудь функции-члене можно ненароком изменить vertexes, а мы этого не хотим. Тогда и добавляем модификатор const.
const int vertexes;
Значение такой переменной можно задать только в списке инициализации конструктора, как и сделано в примере. А вот так даже и не пытайтесь:
Polygon(int v){vertexes = v;} /*ошибка*/
см. также Страуструп 10.4.6.1. "Необходимая инициализация членов"

Второй случай

У нас есть класс Year, и мы хотим, чтобы задаваемый год не выходил за границы диапазона
const int MIN_YEAR = 1900;
const int MAX_YEAR = 2100;
const int DEFAULT_YEAR = 2011;

class Year{
  int year;
public:
  Year(int y);
};

Year::Year(int y){
  if(y < MIN_YEAR || y > MAX_YEAR){
    y = DEFAULT_YEAR;
  }else{
    year = y;
  }
}
Хорошо было бы, если класс не молчал, а как-то предупреждал о выходе за пределы, например генерировал исключение, но это пока не важно. Я хочу поместить эти константы в класс. Способ из предыдущего примера явно не подходит. Тут явно напрашивается связь со статическими членами. Так и есть, можно использовать статические константные члены.
class Year{
  int year;
  static const int MIN_YEAR = 1900;
  static const int MAX_YEAR = 2100;
  static const int DEFAULT_YEAR;
public:
  Year(int y);
};

const int Year::DEFAULT_YEAR = 2011;

Year::Year(int y){
  if(y < MIN_YEAR || y > MAX_YEAR){
    year = DEFAULT_YEAR;
  }else{
    year = y;
  }
}
Обратили внимание, что DEFAULT_YEAR проинициализирован за пределами класса? Да, можно и так. А с дробными, согласно спецификации, только так.

Можно ли объявить дробную константу?

Вопрос относится ко второму случаю, с первым (класс Polygon) все нормально.
Дробную объявить можно, но проинициализировать только аналогично способу инициализации DEFAULT_YEAR. Однако в спецификации нет явного запрета на:
class A{
  static const double PI  = 3.1415;
}
MinGW на это не ругается, VS не знаю. Почему так сложно с дробными? Я и сам не понял, можно почитать ветку форума, там вроде все выяснили.

суббота, 26 сентября 2009 г.

Константы

У Эккеля не зря целая глава выделена под константы. В этой теме много интересного. Сейчас я хочу создать константу и подкопаться к ней через указатели.

const int a = 1;
int b;
cout << &a << &b; //У меня, при запусках, b всегда имеет адрес меньше(на 4 байта), чем a.
int* p = (&b+1); //Это адрес константы a
cout << *p //1
*p = 2; //Меняем
cout << a << endl << *p; //1 2


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