Як ініціалізувати змінну const члена в класі?


105
#include <iostream>

using namespace std;
class T1
{
  const int t = 100;
  public:

  T1()
  {

    cout << "T1 constructor: " << t << endl;
  }
};

Коли я намагаюся ініціалізувати змінну члена const tіз 100. Але це дає мені таку помилку:

test.cpp:21: error: ISO C++ forbids initialization of member t
test.cpp:21: error: making t static

Як я можу ініціалізувати constзначення?


8
з c ++ 11 це можливо перевірити за цим посиланням stackoverflow.com/questions/13662441/…
Капіль

Відповіді:


122

В constзмінної визначає , чи є змінна змінним чи ні. Присвоєне постійне значення буде використовуватися щоразу, коли на цю зміну посилається. Призначене значення не може бути змінено під час виконання програми.

Пояснення Б'ярне Струструпа коротко підсумовує:

Клас, як правило, оголошується у файлі заголовка, а файл заголовка, як правило, включається у багато одиниць перекладу. Однак, щоб уникнути складних правил лінкера, C ++ вимагає, щоб кожен об'єкт мав унікальне визначення. Це правило було б порушено, якби C ++ дозволив визначити об'єкти, які потрібно зберігати в пам'яті як об'єкти, в класі.

constМінлива повинна бути оголошена в класі, але вона не може бути в ньому визначені. Нам потрібно визначити змінну const поза класом.

T1() : t( 100 ){}

Тут призначення t = 100відбувається у списку ініціалізатора задовго до того, як відбудеться ініціалізація класу.


3
Чи можете ви трохи Here the i = 10 assignment in initializer list happens much before the class initilizaiton occurs.розібратися в останньому твердженні, яке я хочу зрозуміти. І в основному такий вид дозволених визначень в класі - це конкретний компілятор?
Чайтанья

3
Що я = 10 завдання?
Даніель Даранас

У мене в класі є константи, які я ініціалізую вище. Однак, коли я намагаюся створити об'єкт цього класу, він дає мені помилку, сказавши, що operator = function not foundу VC ++. У чому може бути проблема?
Rohit Shinde

4
Коли ви використовуєте чиїсь точні слова без атрибуції, це називається плагіатом. Будь ласка , використовуйте правильні атрибути - см stroustrup.com/bs_faq2.html#in-class і stackoverflow.com/questions/13662441 / ...
Tanaya

Так, я також абсолютно не розумію коду у відповіді - що це за чорт? Чи можна розмістити його в реалізації файлів cpp?
Томаш Зато - Відновіть Моніку

50

Що ж, ви могли це зробити static:

static const int t = 100;

або ви можете використовувати ініціалізатор-член:

T1() : t(100)
{
    // Other constructor stuff here
}

2
Для його використання (та / або намірів) було б набагато краще зробити його статичним.
Марк Гарсія

@FredLarson Чи схоже, що деякі версії g ++ не дозволяють такого роду ініціалізації? або Це взагалі не дозволено?
Чайтанья

3
@Chaitanya: C ++ 11 Нестатичні ініціалізатори членів реалізуються з gcc 4.7.
Джессі Добрий

@MarkGarcia чому набагато краще? це може бути на вимогу, якщо він const memberповинен бути доступний з функцій / об'єктів, то чому статичний?
Асиф Муштак

Хоча зазвичай подавати приклад початківцям статики вводить в оману. Тому що вони можуть не знати, що це лише один для всіх примірників (об’єктів) цього класу.
Muhamed Cicak

30

Є кілька способів ініціалізації членів const всередині класу ..

Визначення члена const в цілому потребує ініціалізації змінної ..

1) Всередині класу, якщо ви хочете ініціалізувати const, синтаксис такий

static const int a = 10; //at declaration

2) Другим способом може бути

class A
{
  static const int a; //declaration
};

const int A::a = 10; //defining the static member outside the class

3) Добре, якщо ви не хочете ініціалізуватись при оголошенні, тоді інший спосіб - через конструктор, змінну потрібно ініціалізувати у списку ініціалізації (а не в тілі конструктора). Це повинно бути таким

class A
{
  const int b;
  A(int c) : b(c) {} //const member initialized in initialization list
};

8
Я думаю, що ця відповідь потребує уточнення. Використання статичного ключового слова для члена класу не додає довільного синтаксису, щоб зробити компілятор щасливим. Це означає, що є одна копія змінної для всіх екземплярів об'єкта, постійна чи ні. Це вибір дизайну, який потрібно ретельно продумати. Внизу лінії програміст може вирішити, що цей постійний член класу все ще може змінюватися в залежності від різних об'єктів, незважаючи на те, що залишається постійним протягом життя певного об'єкта.
зновуренко

Погоджено .. Коли ми використовуємо статичну, вона створює лише одну копію її для всіх об’єктів .. Як ви згадали про її вибір дизайну. У випадку єдиної копії для всіх об'єктів 1 і 2 повинні працювати. У випадку індивідуальної копії для кожного об’єкта 3 працювали б
ravs2627

Ця відповідь говорить про просту зміну синтаксису без наслідків - тоді як змінити її на статичну - це не так.
Ісаак Вудс

що робити, якщо вам потрібно використовувати double або float - це частина стандарту C ++ 11?
serup

14

Якщо ви не хочете перетворювати учасника constданих у клас статичним, його можна ініціалізувати за constдопомогою конструктора класу. Наприклад:

class Example{
      const int x;
    public:
      Example(int n);
};

Example::Example(int n):x(n){
}

якщо constв класі є кілька членів даних, ви можете використовувати наступний синтаксис для ініціалізації членів:

Example::Example(int n, int z):x(n),someOtherConstVariable(z){}

3
Я думаю, це дає кращу відповідь, ніж той, який був прийнятий ....
Іван

1
Дякую за кристально чіткі приклади та варіант із множиною! Усунути неоднозначність та додаткові дослідження / прокручування з боку читача!
clearlight

13
  1. Ви можете оновити компілятор до підтримки C ++ 11, і ваш код буде працювати ідеально.

  2. Використовуйте список ініціалізації в конструкторі.

    T1() : t( 100 )
    {
    }

6

Ще одне рішення

class T1
{
    enum
    {
        t = 100
    };

    public:
    T1();
};

Отже, t ініціалізується на 100, і його неможливо змінити, і воно є приватним.


3

Якщо учасником є ​​масив, він буде трохи складнішим, ніж звичайний:

class C
{
    static const int ARRAY[10];
 public:
    C() {}
};
const unsigned int C::ARRAY[10] = {0,1,2,3,4,5,6,7,8,9};

або

int* a = new int[N];
// fill a

class C {
  const std::vector<int> v;
public:
  C():v(a, a+N) {}
};

2

Ще один можливий спосіб - це простори імен:

#include <iostream>

namespace mySpace {
   static const int T = 100; 
}

using namespace std;

class T1
{
   public:
   T1()
   {
       cout << "T1 constructor: " << mySpace::T << endl;
   }
};

Недоліком є ​​те, що інші класи також можуть використовувати константи, якщо вони включають файл заголовка.


1

Це правильний шлях. Ви можете спробувати цей код.

#include <iostream>

using namespace std;

class T1 {
    const int t;

    public:
        T1():t(100) {
            cout << "T1 constructor: " << t << endl;
        }
};

int main() {
    T1 obj;
    return 0;
}

якщо ви користуєтесь, C++10 Compiler or belowви не можете ініціалізувати члена проти на момент декларації. Отже, тут потрібно зробити конструктор для ініціалізації члена даних const. Також необхідно скористатися списком ініціалізатора, T1():t(100)щоб одразу отримати пам'ять.


0

ви можете додати, staticщоб зробити можливою ініціалізацію цієї змінної члена класу.

static const int i = 100;

Однак, це не завжди є хорошою практикою використання всередині класу декларації, оскільки всі об'єкти, встановлені з цього класу, матимуть ту саму статичну змінну, яка зберігається у внутрішній пам'яті за межами пам'яті об'єктів інстанцій.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.