Condividi tramite


Inizializzazione con parentesi graffe

Non è sempre necessario definire un costruttore per un classoggetto , in particolare quelli relativamente semplici. Gli utenti possono inizializzare oggetti di o classstruct utilizzando l'inizializzazione uniforme, come illustrato nell'esempio seguente:

// no_constructor.cpp
// Compile with: cl /EHsc no_constructor.cpp
#include <time.h>

// No constructor
struct TempData
{
    int StationId;
    time_t timeSet;
    double current;
    double maxTemp;
    double minTemp;
};

// Has a constructor
struct TempData2
{
    TempData2(double minimum, double maximum, double cur, int id, time_t t) :
       stationId{id}, timeSet{t}, current{cur}, maxTemp{maximum}, minTemp{minimum} {}
    int stationId;
    time_t timeSet;
    double current;
    double maxTemp;
    double minTemp;
};

int main()
{
    time_t time_to_set;

    // Member initialization (in order of declaration):
    TempData td{ 45978, time(&time_to_set), 28.9, 37.0, 16.7 };

    // When there's no constructor, an empty brace initializer does
    // value initialization = {0,0,0,0,0}
    TempData td_emptyInit{};

    // Uninitialized = if used, emits warning C4700 uninitialized local variable
    TempData td_noInit;

    // Member declaration (in order of ctor parameters)
    TempData2 td2{ 16.7, 37.0, 28.9, 45978, time(&time_to_set) };

    return 0;
}

Quando un class oggetto o struct non dispone di un costruttore, specificare gli elementi dell'elenco nell'ordine in cui i membri vengono dichiarati in class. Se ha class un costruttore, specificare gli elementi nell'ordine dei parametri. Se un tipo ha un costruttore predefinito, dichiarato in modo implicito o esplicito, è possibile usare l'inizializzazione tra parentesi graffe con parentesi graffe vuote per richiamarla. Ad esempio, è possibile inizializzare quanto segue class usando l'inizializzazione di parentesi graffe vuota e non vuota:

#include <string>
using namespace std;

class class_a {
public:
    class_a() {}
    class_a(string str) : m_string{ str } {}
    class_a(string str, double dbl) : m_string{ str }, m_double{ dbl } {}
double m_double;
string m_string;
};

int main()
{
    class_a c1{};
    class_a c1_1;

    class_a c2{ "ww" };
    class_a c2_1("xx");

    // order of parameters is the same as the constructor
    class_a c3{ "yy", 4.4 };
    class_a c3_1("zz", 5.5);
}

Se la classe dispone di costruttori non predefiniti, l'ordine in cui i membri della classe vengono visualizzati nell'inizializzatore con parentesi graffe è l'ordine in cui appaiono i parametri corrispondenti nel costruttore, non l'ordine in cui i membri vengono dichiarati (come nel caso di class_a nell'esempio precedente). In caso contrario, se il tipo non ha un costruttore dichiarato, gli inizializzatori di membro devono essere visualizzati nell'inizializzatore di parentesi graffe nello stesso ordine in cui vengono dichiarati. In questo caso, è possibile inizializzare il numero di membri pubblici desiderati, ma non è possibile ignorare alcun membro. L'esempio seguente mostra l'ordine usato nell'inizializzazione tra parentesi graffe quando non è presente un costruttore dichiarato:

class class_d {
public:
    float m_float;
    string m_string;
    wchar_t m_char;
};

int main()
{
    class_d d1{};
    class_d d1{ 4.5 };
    class_d d2{ 4.5, "string" };
    class_d d3{ 4.5, "string", 'c' };

    class_d d4{ "string", 'c' }; // compiler error
    class_d d5{ "string", 'c', 2.0 }; // compiler error
}

Se il costruttore predefinito viene dichiarato in modo esplicito, ma contrassegnato come eliminato, non è possibile usare l'inizializzazione delle parentesi graffe vuote:

class class_f {
public:
    class_f() = delete;
    class_f(string x): m_string { x } {}
    string m_string;
};
int main()
{
    class_f cf{ "hello" };
    class_f cf1{}; // compiler error C2280: attempting to reference a deleted function
}

È possibile usare l'inizializzazione tra parentesi graffe in qualsiasi punto in cui in genere si esegue l'inizializzazione, ad esempio come parametro di funzione o come valore restituito o con la new parola chiave :

class_d* cf = new class_d{4.5};
kr->add_d({ 4.5 });
return { 4.5 };

In /std:c++17 modalità e versioni successive, le regole per l'inizializzazione delle parentesi graffe vuote sono leggermente più restrittive. Vedere Costruttori derivati e inizializzazione estesa dell'aggregazione.

costruttori initializer_list

La classe initializer_list rappresenta un elenco di oggetti di un tipo specificato che può essere utilizzato in un costruttore e in altri contesti. È possibile creare un initializer_list tramite l'inizializzazione con parentesi graffe:

initializer_list<int> int_list{5, 6, 7};

Importante

Per usare questa classe, è necessario includere l'intestazione <initializer_list> .

Un initializer_list può essere copiato. In questo caso, i membri del nuovo elenco sono riferimenti ai membri dell'elenco originale:

initializer_list<int> ilist1{ 5, 6, 7 };
initializer_list<int> ilist2( ilist1 );
if (ilist1.begin() == ilist2.begin())
    cout << "yes" << endl; // expect "yes"

Le classi di contenitori di libreria standard e string, wstring e regex, dispongono di costruttori initializer_list. Negli esempi seguenti viene illustrato come effettuare l'inizializzazione con parentesi graffe con questi costruttori:

vector<int> v1{ 9, 10, 11 };
map<int, string> m1{ {1, "a"}, {2, "b"} };
string s{ 'a', 'b', 'c' };
regex rgx{ 'x', 'y', 'z' };

Vedi anche

Classi e struct
Costruttori