Jak zainicjować zmienną składową const w klasie?

105
#include <iostream>

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

  T1()
  {

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

Kiedy próbuję zainicjować zmienną składową const wartością t100. Ale powoduje to następujący błąd:

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

Jak mogę zainicjować constwartość?

Chaitanya
źródło
8
z c ++ 11 jest to możliwe, sprawdź ten link stackoverflow.com/questions/13662441/…
Kapil

Odpowiedzi:

123

Plik const zmienna określa czy zmienna jest modyfikowalny czy nie. Przypisana stała wartość będzie używana przy każdym odwołaniu do zmiennej. Przypisanej wartości nie można modyfikować podczas wykonywania programu.

Wyjaśnienie Bjarne Stroustrupa podsumowuje to krótko:

Klasa jest zwykle deklarowana w pliku nagłówkowym, a plik nagłówkowy jest zwykle dołączany do wielu jednostek tłumaczeniowych. Jednak aby uniknąć skomplikowanych reguł konsolidatora, C ++ wymaga, aby każdy obiekt miał unikalną definicję. Ta reguła zostałaby złamana, gdyby C ++ pozwolił na definiowanie w klasie jednostek, które musiałyby być przechowywane w pamięci jako obiekty.

constZmienna musi zostać zadeklarowana w klasie, ale to nie może być zdefiniowana w nim. Musimy zdefiniować zmienną const poza klasą.

T1() : t( 100 ){}

Tutaj przypisanie t = 100odbywa się na liście inicjalizatorów, dużo wcześniej niż inicjalizacja klasy.

Dinkar Thakur
źródło
3
Możesz trochę rozwinąć ostatnie stwierdzenie? Here the i = 10 assignment in initializer list happens much before the class initilizaiton occurs.Nie rozumiem. I zasadniczo tego rodzaju dopuszczanie definicji w klasie jest specyficzne dla kompilatora, prawda?
Chaitanya,
3
Co ja = 10 przydziałów?
Daniel Daranas,
W mojej klasie mam stałe, które inicjalizuję w powyższy sposób. Jednak kiedy próbuję stworzyć obiekt tej klasy, wyświetla mi się błąd mówiąc, że operator = function not foundw VC ++. Jaki może być problem?
Rohit Shinde
4
Kiedy używasz czyichś dokładnych słów bez podania źródła, nazywa się to plagiatem. Prosimy o właściwe przypisanie - patrz stroustrup.com/bs_faq2.html#in-class i stackoverflow.com/questions/13662441/…
Tanaya,
Tak, zupełnie nie rozumiem kodu w odpowiedzi - co to do cholery jest? Czy można go umieścić w implementacji pliku cpp?
Tomáš Zato - Przywróć Monikę
50

Cóż, możesz to zrobić static:

static const int t = 100;

lub możesz użyć inicjatora członka:

T1() : t(100)
{
    // Other constructor stuff here
}
Fred Larson
źródło
2
Na jego użytek (i / lub intencje) znacznie lepiej byłoby uczynić go statycznym.
Mark Garcia
@FredLarson Czy to tak, jakby niektóre wersje g ++ nie zezwalały na tego rodzaju inicjalizacje? czy w ogóle nie jest dozwolone?
Chaitanya,
3
@Chaitanya: C ++ 11 Niestatyczne inicjatory składowe są zaimplementowane od gcc 4.7.
Jesse Good
@MarkGarcia, dlaczego znacznie lepiej? może być na żądanie, jeśli const memberpowinien być dostępny z funkcji / obiektów, to dlaczego statyczny?
Asif Mushtaq
Chociaż zwykle podawanie przykładu początkującym statkom jest mylące. Ponieważ mogą nie wiedzieć, że jest to tylko jeden dla wszystkich instancji (obiektów) tej klasy.
Muhamed Cicak
30

Istnieje kilka sposobów na zainicjowanie elementów stałych wewnątrz klasy.

Definicja elementu const w ogóle wymaga również inicjalizacji zmiennej.

1) Wewnątrz klasy, jeśli chcesz zainicjować const, składnia jest następująca

static const int a = 10; //at declaration

2) Drugi sposób może być

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

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

3) Cóż, jeśli nie chcesz inicjalizować w deklaracji, to w przeciwnym razie za pomocą konstruktora zmienna musi zostać zainicjalizowana na liście inicjalizacyjnej (a nie w treści konstruktora). Tak musi być

class A
{
  const int b;
  A(int c) : b(c) {} //const member initialized in initialization list
};
ravs2627
źródło
8
Myślę, że ta odpowiedź wymaga wyjaśnienia. Użycie słowa kluczowego static dla elementu członkowskiego klasy nie dodaje jakiejś arbitralnej składni, aby uszczęśliwić kompilator. Oznacza to, że istnieje jedna kopia zmiennej dla wszystkich wystąpień obiektu, stała lub nie. Jest to wybór projektowy, który należy dokładnie przemyśleć. W dalszej kolejności programista może zdecydować, że ten stały element klasy może nadal zmieniać się z różnymi obiektami, mimo że pozostaje niezmienny przez cały okres istnienia danego obiektu.
opetrenko
Zgoda… Kiedy używamy statycznego, tworzy tylko jedną kopię dla wszystkich obiektów. Jak wspomniałeś, jest to wybór projektu. W przypadku pojedynczego egzemplarza dla wszystkich obiektów 1 i 2 powinny działać. W przypadku indywidualnej kopii dla każdego obiektu, działałoby 3
ravs2627
Ta odpowiedź sugeruje prostą zmianę składni bez konsekwencji - podczas gdy zmiana jej na statyczną nie jest.
Isaac Woods
co, jeśli musisz użyć double lub float - czy jest to część standardu C ++ 11?
serup
14

Jeśli nie chcesz, aby element constczłonkowski danych w klasie był statyczny, możesz zainicjować element constczłonkowski danych przy użyciu konstruktora klasy. Na przykład:

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

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

jeśli constw klasie jest wielu członków danych, możesz użyć następującej składni, aby zainicjować członków:

Example::Example(int n, int z):x(n),someOtherConstVariable(z){}
GANESH BK
źródło
3
Myślę, że to zapewnia lepszą odpowiedź niż ta, która została zaakceptowana ....
Ian
1
Dziękuję za krystalicznie jasne przykłady i wariant pokazujący wielość! Wyeliminowano dwuznaczność i dodatkowe badania / przewijanie ze strony czytelnika!
jasne światło
13
  1. Możesz zaktualizować swój kompilator do obsługi C ++ 11, a Twój kod będzie działał idealnie.

  2. Użyj listy inicjalizacyjnej w konstruktorze.

    T1() : t( 100 )
    {
    }
borisbn
źródło
6

Innym rozwiązaniem jest

class T1
{
    enum
    {
        t = 100
    };

    public:
    T1();
};

Więc t jest inicjalizowane na 100 i nie można go zmienić i jest prywatne.

Piżmowy
źródło
3

Jeśli element członkowski jest tablicą, będzie nieco złożony niż normalnie:

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};

lub

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

class C {
  const std::vector<int> v;
public:
  C():v(a, a+N) {}
};
Viet Anh Do
źródło
2

Innym możliwym sposobem są przestrzenie nazw:

#include <iostream>

namespace mySpace {
   static const int T = 100; 
}

using namespace std;

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

Wadą jest to, że inne klasy mogą również używać stałych, jeśli zawierają plik nagłówkowy.

Baran
źródło
1

To jest właściwy sposób. Możesz wypróbować ten kod.

#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;
}

jeśli używasz C++10 Compiler or below, nie możesz zainicjować członka przeciwnika w momencie deklaracji. Więc tutaj należy utworzyć konstruktor, aby zainicjować składową danych const. Konieczne jest również użycie listy inicjatorów, T1():t(100)aby natychmiast uzyskać pamięć.

Gambler Aziz
źródło
0

możesz dodać, staticaby umożliwić inicjalizację tej zmiennej składowej klasy.

static const int i = 100;

Jednak nie zawsze jest to dobra praktyka w użyciu wewnątrz deklaracji klasy, ponieważ wszystkie obiekty instacowane z tej klasy będą współdzieliły tę samą zmienną statyczną, która jest przechowywana w pamięci wewnętrznej poza pamięcią zakresu obiektów, dla których utworzono instancję.

dhokar.w
źródło