Jednotná inicializace a delegování konstruktorů
V moderním jazyce C++, můžete použít Inicializace složená závorka pro každý typ bez znaménka rovná se.Také můžete použít delegování konstruktory pro zjednodušení kódu, pokud máte více konstruktorů, které provádějí podobné práce.
Inicializace složená závorka
Inicializace závorky můžete použít pro libovolné třídy, struktury nebo unie.Pokud typ nemá výchozí konstruktor, implicitně nebo explicitně deklarovány, můžete použít výchozí složená závorka inicializace (s prázdné složené závorky).Například následující třída může být inicializována pomocí výchozí a inicializace nestandardní závorky:
#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);
}
Pokud třída není výchozí konstruktory, pořadí členů v které třídě v inicializátoru složená závorka je pořadí, ve kterém se zobrazí odpovídající parametry v konstruktoru, není pořadí, ve kterém jsou deklarovány členů (stejně jako u class_a v předchozím příkladu).Jinak Pokud typ nemá žádný konstruktor deklarované, pořadí členů v inicializátoru složená závorka je stejné jako pořadí, ve kterém jsou deklarovány; v takovém případě bude možné inicializovat tolik veřejné členy jak chcete, ale každý člen nelze přeskočit.Následující příklad ukazuje pořadí, ve kterém se používá při inicializaci složená závorka po žádný konstruktor deklarované:
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
}
Pokud výchozí konstruktor explicitně deklarovat, ale označeny jako odstraněné, nelze použít výchozí složená závorka inicializace:
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
}
Inicializace závorky můžete použít kdekoli by obvykle provádí inicializace – například jako parametr funkce nebo vrácené hodnoty nebo se new klíčové slovo:
class_d* cf = new class_d{4.5};
kr->add_d({ 4.5 });
return { 4.5 };
initializer_list konstruktory
initializer_list Class Představuje seznam objektů zadaného typu, který lze použít v konstruktoru a v jiných kontextech.Initializer_list můžete vytvořit pomocí inicializace složená závorka:
initializer_list<int> int_list{5, 6, 7};
Důležité |
---|
K použití této třídy, je nutné zahrnout <initializer_list> záhlaví. |
initializer_list Může být kopírován.Nový seznam členů v tomto případě jsou odkazy na původní seznam členů:
initializer_list<int> ilist1{ 5, 6, 7 };
initializer_list<int> ilist2( ilist1 );
if (ilist1.begin() == ilist2.begin())
cout << "yes" << endl; // expect "yes"
Kontejner třídy standardní knihovny a také string, wstring, a regex, mají initializer_list konstruktory.Následující příklady ukazují, jak se tyto konstruktory inicializace složená závorka:
vector<int> v1{ 9, 10, 11 };
map<int, string> m1{ {1, "a"}, {2, "b"} };
string s{ 'a', 'b', 'c' };
regex rgx{'x', 'y', 'z'};
Delegování konstruktorů
Mnoho tříd mají více konstruktory, které podobným způsobem, například ověření parametrů:
class class_c {
public:
int max;
int min;
int middle;
class_c() {}
class_c(int my_max) {
max = my_max > 0 ? my_max : 10;
}
class_c(int my_max, int my_min) {
max = my_max > 0 ? my_max : 10;
min = my_min > 0 && my_min < max ? my_min : 1;
}
class_c(int my_max, int my_min, int my_middle) {
max = my_max > 0 ? my_max : 10;
min = my_min > 0 && my_min < max ? my_min : 1;
middle = my_middle < max && my_middle > min ? my_middle : 5;
}
};
Opakované kód by mohl snížit přidáním funkce, která neprovádí ověřování, ale kód pro všechny class_c bude možné snadněji pochopit a udržovat pokud jeden konstruktor může delegovat některé úkoly na jiné.Přidat delegování konstruktory, použijte constructor (. . .) : constructor (. . .) syntaxe:
class class_c {
public:
int max;
int min;
int middle;
class_c(int my_max) {
max = my_max > 0 ? my_max : 10;
}
class_c(int my_max, int my_min) : class_c(my_max) {
min = my_min > 0 && my_min < max ? my_min : 1;
}
class_c(int my_max, int my_min, int my_middle) : class_c (my_max, my_min){
middle = my_middle < max && my_middle > min ? my_middle : 5;
}
};
int main() {
class_c c1{ 1, 3, 2 };
}
Krocích v předchozím příkladu, Všimněte si, že konstruktoru class_c(int, int, int) nejprve volá konstruktor class_c(int, int), která zase volá class_c(int).Každá z konstruktorů provádí pouze práce neprovádí jiné konstruktory.
První konstruktor, který se nazývá inicializuje objekt tak, aby všichni jeho členové jsou inicializovány v daném okamžiku.Nelze provádět členské inicializace v konstruktor, který přenese do jiného konstruktoru, jak je znázorněno zde:
class class_a {
public:
class_a() {}
// member initialization here, no delegate
class_a(string str) : m_string{ str } {}
//can’t do member initialization here
// error C3511: a call to a delegating constructor shall be the only member-initializer
class_a(string str, double dbl) : class_a(str) , m_double{ dbl } {}
// only member assignment
class_a(string str, double dbl) : class_a(str) { m_double = dbl; }
double m_double{ 1.0 };
string m_string;
};
Následující příklad ukazuje použití nestatické členy dat inicializátory.Všimněte si, že pokud konstruktor inicializuje také určitý datový člen, je přepsána inicializátor člen:
class class_a {
public:
class_a() {}
class_a(string str) : m_string{ str } {}
class_a(string str, double dbl) : class_a(str) { m_double = dbl; }
double m_double{ 1.0 };
string m_string{ m_double < 10.0 ? "alpha" : "beta" };
};
int main() {
class_a a{ "hello", 2.0 }; //expect a.m_double == 2.0, a.m_string == "hello"
int y = 4;
}
Syntaxe delegování konstruktoru nezabrání se zamezí nechtěnému vytvoření rekurze konstruktoru, volá Constructor1 Constructor2, která volá Constructor1 – a nejsou vyvolány žádné chyby, dokud není přetečení zásobníku.Je vaší odpovědností, aby se zabránilo cyklů.
class class_f{
public:
int max;
int min;
// don't do this
class_f() : class_f(6, 3){ }
class_f(int my_max, int my_min) : class_f() { }
};