Açar söz nə deməkdir?

C ++-dakı explicit sözü nə deməkdir?

2387
23 сент. Skizz tərəfindən 23 Sentyabrda təyin olundu 2008-09-23 16:58 '08 at 4:58 pm 2008-09-23 16:58
@ 11 cavab

Cədvəl funksiyasının parametrlərini həll etmək üçün bir örtük dönüşüm yerinə yetirmək üçün icazə verilir. Bu, derleyici parametr üçün düzgün bir növü almaq üçün bir növdən digərinə çevirmək üçün bir parametr ilə çağırılan konstruktorları istifadə edə biləcəyini bildirir.

Burada örtülü dönüşümlər üçün istifadə edilə bilən bir konstruktor nümunəsi olan sinifdir:

 class Foo { public: // single parameter constructor, can be used as an implicit conversion Foo (int foo) : m_foo (foo) { } int GetFoo () { return m_foo; } private: int m_foo; }; 

Foo obyektini qəbul edən sadə bir funksiya:

 void DoBar (Foo foo) { int i = foo.GetFoo (); } 

və burada DoBar funksiyası DoBar .

 int main () { DoBar (42); } 

Dəlil Foo obyekti deyil, << 26> deyil. Bununla belə, Foo qəbul edən Foo üçün bir konstruktor var, buna görə də bu int parametrləri düzgün şəkildə çevirmək üçün istifadə edilə bilər.

Derleyiciye hər parametr üçün bunu bir dəfə etməyə icazə verilir.

Quraşdırıcıya explicit olan sözün öneküsü, derleyicinin örtük dönüşümler üçün bu yapıcıyı istifadə etməsini maneə törədir. Yuxarıdakı sinifə əlavə etmək DoBar (42) funksiyasını çağırarkən bir DoBar (42) . İndi DoBar (Foo (42)) istifadə edərək, DoBar (Foo (42)) zəng etmək lazımdır.

Bunu etmək istədiyiniz səbəb səhvlərin gizlənə biləcək təsadüfən qurulmamasıdır. Düşüncə nümunəsi:

  • Bir class MyString(int size) bir MyString(int size) bir string qurur bir konstruktoru var. Bir print(const MyString> funksiyası var və siz print(3) çağırırsınız print(3) (əslində print("3") zəng etmək niyyətində olduğunuzda print("3") ). Siz "3" yazmaq üçün gözlədiyiniz, lakin bunun yerinə boşluq 3 uzunluğu yazır.
2778
23 сент. cavab skizinə verilir. 2008-09-23 16:59 '08 at 4:59 pm 2008-09-23 16:59

Bir String sinifiniz olduğunu düşünün:

 class String { public: String(int n); // allocate n bytes to the String object String(const char *p); // initializes object with char *p }; 

İndi cəhd edin:

border=0
 String mystring = 'x'; 

'x' xarakteri birbaşa int'a çevriləcək və sonra String(int) çağırılacaq. Amma bu, istifadəçi nəyə qadir deyil. Belə şəraitin qarşısını almaq üçün biz konstruktoru explicit müəyyən edəcəyik:

 class String { public: explicit String (int n); //allocate n bytes String(const char *p); // initialize sobject with string p }; 
971
23 сент. Cavab 23 sentyabr Eddie tərəfindən verilir 2008-09-23 17:09 '08 saat 05:09 'de 2008-09-23 17:09

C ++-da bir tələb olunan parametrə malik olan bir konstruktor örtülü bir dönüşüm funksiyası hesab olunur. Parametr tipini sinif tipinə çevirir. Bu yaxşı bir şey olsun ya da olmasın, konstruktorun semantikasından asılıdır.

Məsələn, bir String(const char* s) konstruktoru String(const char* s) ilə bir string sinfi varsa, bəlkə də istədiyiniz nədir. const char* funksiyasını bir String gözləyir və kompilyator avtomatik olaraq sizin üçün müvəqqəti String obyekti yaradır.

Digər tərəfdən, bir arabellek sınıfınız varsa, Buffer(int size) konstruktor baytlarda bufer ölçüsünü alır, ehtimal ki, kompilyatorun int Buffer s üçün asanlıqla çevirilməsini istəmirsiniz. Bunun qarşısını almaq üçün, açar sözü ilə konstruktor elan edirik:

 class Buffer { explicit Buffer(int size); ... } 

Beləliklə,

 void useBuffer(Buffer buf); useBuffer(4); 

kompilyasiya zamanı səhvidir. Müvəqqəti Buffer obyektindən keçmək istəyirsinizsə, bunu açıq şəkildə etməlisiniz:

 useBuffer(Buffer(4)); 

Beləliklə, əgər bir parametrli konstruktor parametrinizi sinfi bir obyektinə çevirirsə, ehtimal ki, açar sözü explicit istifadə etmək istəmirsiniz. Ancaq yalnız bir parametrenin alındığı bir konstruktor varsa, onu explicit bildirməlisiniz, belə ki, kompilyator sizi gözlənilməz dönüşümlərlə təəccübləndirməyəcək.

133
23 сент. cavab cjm 23 sep verilir . 2008-09-23 19:37 '08 at 7:37 pm 2008-09-23 19:37

Bu cavab başqa bir cavabda nəzərə alınmadığından, açıq bir konstruktor olmayan / obyektin yaradılmasına aiddir.

Aşağıdakı sinfi açıq konstruktor olmadan nəzərdən keçirin:

 class Foo { public: Foo(int x) : m_x(x) { } private: int m_x; }; 

Foo sinifinin obyektləri iki şəkildə yaradıla bilər:

 Foo bar1(10); Foo bar2 = 20; 

Tətbiqdən asılı olaraq, Foo sinifinin bir nümunəsi yaratmaq üçün ikinci yol şübhəli ola bilər, ya da proqramçı nə planlaşdırır. Foo bar2 = 20; explicit prefiksi Foo bar2 = 20; də bir kompilyator səhvi yaradır Foo bar2 = 20; ,

Ümumiyyətlə, tətbiq etməyi qadağan etmədikdə, konstruktorları bir arqumentlə explicit elan etmək yaxşı bir praktikdir.

İlə inşaatçılar da unutmayın

  • bütün parametrlər üçün və ya
  • ikinci parametr üçün default arqumentlər

həm də bir arqumentlə qurucu olaraq istifadə edilə bilər. Buna görə də bunu explicit edə bilərsiniz.

Misal üçün, konstruktorunuzu bir arqumentlə qəsdən istəmirsinizsə, bir funksiyanı yaratsanız ( bu cavabda elan edilmiş add_x strukturuna baxın). Bu halda, add_x add30 = 30; kimi bir obyekt yaradılır add_x add30 = 30; Yəqin məntiqə sahibdir.

Burada dəqiq konstruktorların yaxşı bir rekordudur.

34
08 окт. Cavab Gautam Oct 08. 2013-10-08 17:43 '13 at 17:43 2013-10-08 17:43

Açar sözü, dönüşüm konstruktorunu qeyri-dönüşüm explicit edir. Nəticədə kod daha az səhvdir.

32
21 нояб. Cavab 21 noyabrda SankararaoMajji tərəfindən verilir. 2012-11-21 05:36 '12 at 5:36 pm 2012-11-21 05:36

Açar söz ya da müşayiət olunur

  • X tipli birinci (yalnız) parametrini örtük şəkildə çevirmək üçün istifadə edilə bilməyən X sinifinin qurucusu

C ++ [class.conv.ctor]

1) açıq bir funksiya spesifikasiyasız elan edilən konstruktor onun parametrlərinin növündən onun sinfi tipinə çevrilməsini müəyyənləşdirir. Belə bir konstruktor çevrilmə konstruktoru adlanır.

2) açıq konstruktor örtük konstruktorlarla eyni şəkildə obyektlər qurur, lakin yalnız düz başlatma sintaksisinin (8.5) açıq şəkildə istifadə edildiyi və ya istifadə edildiyi yerlərdə (5.2.9, 5.4) istifadə edildikdə. Varsayılan konstruktor aydın konstruktor ola bilər; belə bir konstruktor təyinatın başlanmasını və ya dəyərin təyin edilməsini yerinə yetirmək üçün istifadə ediləcək (8.5).

  • yalnız birbaşa başlanğıc və açıq çevrilmə üçün nəzərdə tutulan bir dönüşüm funksiyası.

C ++ [class.conv.fct]

2) Dönüştürmə funksiyası açıq ola bilər (7.1.2), bu halda yalnız birbaşa başlanğıc üçün xüsusi bir dönüşüm hesab olunur (8.5). Əks təqdirdə, istifadəçi müəyyən edilmiş dəyişikliklər tapşırıq və başlama ilə məhdudlaşmır.

Baxın

Aydın transformativ funksiyalar və konstruktorlar yalnız açıq transformasiyalar üçün (doğrudan başlatma və ya açıq döküm əməliyyatı) istifadə edilə bilər, örtük konstruktorlar və transform funksiyaları həm açıq, həm də açıq transformasiyalar üçün istifadə oluna bilər.

  

X, Y, Z strukturlarını və funksiyalarını foo, bar, baz istifadə nümunəsi:

explicit və qeyri- explicit arasındakı fərqləri görmək üçün strukturların və funksiyaların kiçik konfiqurasiyasına baxın.

 struct Z { }; struct X { explicit X(int a); // X can be constructed from int explicitly explicit operator Z (); // X can be converted to Z explicitly }; struct Y{ Y(int a); // int can be implicitly converted to Y operator Z (); // Y can be implicitly converted to Z }; void foo(X x) { } void bar(Y y) { } void baz(Z z) { } 

Dizayn nümunələri:

Function argument conversion:

 foo(2); // error: no implicit conversion int to X possible foo(X(2)); // OK: direct initialization: explicit conversion foo(static_cast<X>(2)); // OK: explicit conversion bar(2); // OK: implicit conversion via Y(int) bar(Y(2)); // OK: direct initialization bar(static_cast<Y>(2)); // OK: explicit conversion 

Obyektin başlanğıcı:

 X x2 = 2; // error: no implicit conversion int to X possible X x3(2); // OK: direct initialization X x4 = X(2); // OK: direct initialization X x5 = static_cast<X>(2); // OK: explicit conversion Y y2 = 2; // OK: implicit conversion via Y(int) Y y3(2); // OK: direct initialization Y y4 = Y(2); // OK: direct initialization Y y5 = static_cast<Y>(2); // OK: explicit conversion 

Dönüşüm funksiyalarının nümunələri:

 X x1{ 0 }; Y y1{ 0 }; 

Function argument conversion:

 baz(x1); // error: X not implicitly convertible to Z baz(Z(x1)); // OK: explicit initialization baz(static_cast<Z>(x1)); // OK: explicit conversion baz(y1); // OK: implicit conversion via Y::operator Z() baz(Z(y1)); // OK: direct initialization baz(static_cast<Z>(y1)); // OK: explicit conversion 

Obyektin başlanğıcı:

 Z z1 = x1; // error: X not implicitly convertible to Z Z z2(x1); // OK: explicit initialization Z z3 = Z(x1); // OK: explicit initialization Z z4 = static_cast<Z>(x1); // OK: explicit conversion Z z1 = y1; // OK: implicit conversion via Y::operator Z() Z z2(y1); // OK: direct initialization Z z3 = Z(y1); // OK: direct initialization Z z4 = static_cast<Z>(y1); // OK: explicit conversion 

Niyə çevrilməsi funksiyaları və ya explicit konstruktorlardan istifadə edirsiniz?

Dönüşüm konstruktorları və örtülü çevrilmə funksiyaları qeyri-müəyyənliyə səbəb ola bilər.

İntenə çevrilmiş V strukturunu, V nin örtük strukturunu və Ubool üçün çox yüklənmiş funksiyasını nəzərə alın.

 struct V { operator bool() const { return true; } }; struct U { U(V) { } }; void f(U) { } void f(bool) { } 

V tipli bir obyektdən keçərkən zəng birmənalı deyil V

 V x; f(x); // error: call of overloaded 'f(V is ambiguous 

Derleyici, bir V konusunu f'ye keçmək üçün bir növə çevirmək üçün bir U konstruktorunu və ya çevrilmə funksiyasından istifadə etmək istəmədiyini bilmir.

Əgər ya konstruktor U və ya V dönüşüm funksiyası explicit olsa, onda yalnız örtülü çevrilmə nəzərdən keçiriləcəyi üçün heç bir qeyri-müəyyənlik olmayacaqdır. Hər ikisi də aydındırsa, V tipli bir obyektin istifadə edərək, f çağırışı açıq bir dönüşüm və ya bir döküm əməliyyatından istifadə edilməlidir.

Dönüşüm konstruktorları və örtülü dönüşüm funksiyaları gözlənilməz davranışa səbəb ola bilər.

Vektorun çap funksiyasını nəzərdən keçirin:

 void print_intvector(std::vector<int> const  { for (int x : v) std::cout << x << '\n'; } 

Vektor konstruktor ölçüsü açıq olmazsa belə bir funksiya çağırılmalıdır:

 print_intvector(3); 

Belə bir çağırışdan nə gözləmək olar? Bir satırda 3 və ya üç xətt var mı? (İkincinin olduğu yerdə nə olur?)

Sınıf interfeysində açıq bir söz istifadə edərək, istifadəçi interfeysi istənilən çevrimi açıq şəkildə müəyyənləşdirməyə məcbur edir.

Bjarne Straustrup yazdığı kimi (C ++ Proqramlaşdırma dili, 4-cü ed., 35.2.1, s. 1011), std::duration səbəbinin əsas sayından tam olaraq inşa edilə bilməməsi məsələsi:

Nə demək istədiyinizi bilsəniz, bu barədə açıq danışın.

31
11 июля '15 в 2:48 2015-07-11 02:48 Cavab Pixelchemist tərəfindən iyul ayının 11-də saat 2 : 48- də verilir

explicit bir konstruktorun açıq-aşkar çağırılmasını məcbur etmək üçün istifadə edilə bilər.

 class C{ public: explicit C(void) = default; }; int main(void){ C c(); return 0; } 

C(void) konstruktorunun C(void) əvvəlcədən açıq sözü, bu konstruktorun yalnız açıq bir çağırışına icazə verdiyini bildirir.

explicit açar söz açarı da xüsusi növ dönüşüm əməliyyatlarında istifadə edilə bilər:

 class C{ public: explicit inline operator bool(void) const{ return true; } }; int main(void){ C c; bool b = static_cast<bool>(c); return 0; } 

Burada, explicit sözü yalnız açıq bir hərəkətə tətbiq edilir, bool b = c; bu halda etibarsız olacaq. Bu cür hallarda, explicit söz proqramçıya gizli, arzuolunmaz dalğalardan çəkinməyə kömək edə bilər. Bu istifadə C ++ 11-də standartlaşdırılır.

25
14 мая '13 в 12:28 2013-05-14 12:28 Cavab 14 may 2013- cü il saat 12.23-Helixirr tərəfindən verilir

Bu artıq müzakirə edilmişdir ( açıq konstruktor nədir ). Ancaq deyə bilərəm ki, burada aşkar edilmiş ətraflı təsvirləri yoxdur.

Bundan əlavə, həmişə olduğu kimi, öz arqumentlərini qurucular (arg2, arg3, ... üçün default dəyərləri olanlar da daxil etmək) üçün yaxşı kodlaşdırma praktikasıdır. Həmişə olduğu kimi C ++ ilə: bunu etməsəniz, etməyi istəyə ...

Dərslər üçün daha yaxşı bir təcrübə, həqiqətən, həyata keçirmək lazım deyilsə, çıxarmaq və təyin etmək xüsusi (aka onu aradan). Bu, C ++-nun sizin üçün yaratdığı üsullardan istifadə edərkən göstəricilərin mümkün nüsxələrini qaçırır. Bunun bir başqa yolu da bir təkan əldə etməkdir: qeyri-sənədsizdir.

17
02 окт. cavab 02 oktyabr tarixində verilir . 2009-10-02 01:00 '09 saat 01:00 'da 2009-10-02 01:00

Link Cpp həmişə faydalıdır! Açıq spesifikator haqqında ətraflı məlumat burada tapa bilərsiniz . Gizli dönüşümlərəsurəti-başlanmalara baxmaq lazımdır.

Tez baxın

Açıq göstərici göstərir ki, konstruktor və ya dönüşüm funksiyası (C ++ 11) bu nüsxənin örtük çevrilməsinə və ya başlanmasına imkan vermir.

Bir nümunə belədir:

 struct A { A(int) { } // converting constructor A(int, int) { } // converting constructor (C++11) operator bool() const { return true; } }; struct B { explicit B(int) { } explicit B(int, int) { } explicit operator bool() const { return true; } }; int main() { A a1 = 1; // OK: copy-initialization selects A::A(int) A a2(2); // OK: direct-initialization selects A::A(int) A a3 {4, 5}; // OK: direct-list-initialization selects A::A(int, int) A a4 = {4, 5}; // OK: copy-list-initialization selects A::A(int, int) A a5 = (A)1; // OK: explicit cast performs static_cast if (a1) cout << "true" << endl; // OK: A::operator bool() bool na1 = a1; // OK: copy-initialization selects A::operator bool() bool na2 = static_cast<bool>(a1); // OK: static_cast performs direct-initialization // B b1 = 1; // error: copy-initialization does not consider B::B(int) B b2(2); // OK: direct-initialization selects B::B(int) B b3 {4, 5}; // OK: direct-list-initialization selects B::B(int, int) // B b4 = {4, 5}; // error: copy-list-initialization does not consider B::B(int,int) B b5 = (B)1; // OK: explicit cast performs static_cast if (b5) cout << "true" << endl; // OK: B::operator bool() // bool nb1 = b2; // error: copy-initialization does not consider B::operator bool() bool nb2 = static_cast<bool>(b2); // OK: static_cast performs direct-initialization } 
15
20 авг. Cavab 20 avqustda selfboot verilir 2016-08-20 15:45 '16 saat 15:45 'də 2016-08-20 15:45

Açıq dönüşüm qurucular (yalnız C ++)

Açıq funksiyanı göstərən istənməyən örtük çevrilmə növünü nəzarət edir. Yalnız bir sinif bəyannaməsində konstruktiv deklarasiyalarda istifadə edilə bilər. Məsələn, konstruktordan başqa, növbəti sinifdə olan konstruktorlar Konstruktorun transformasiyasıdır.

 class A { public: A(); A(int); A(const char*, int = 0); }; 

Aşağıdakı reklamlar qanuni:

 A c = 1; A d = "Venditti"; 

Birinci bəyanat A c = A( 1 ); bərabərdir A c = A( 1 ); .

Əgər bir sinif konstruktorunu explicit olaraq elan edirsinizsə, əvvəlki bəyanatlar qanunsuz olardı.

Məsələn, əgər bir sinif elan edirsinizsə:

 class A { public: explicit A(); explicit A(int); explicit A(const char*, int = 0); }; 

Yalnız sinif tipi dəyərlərinə uyğun dəyərlər təyin edə bilərsiniz.

Məsələn, aşağıdakı bəyanatlar qanunilidir:

  A a1; A a2 = A(1); A a3(1); A a4 = A("Venditti"); A* p = new A(1); A a5 = (A)1; A a6 = static_cast<A>(1); 
10
20 дек. Cavab coding_ninza 20 dekabr verilir. 2017-12-20 15:19 '17 də 15:19 2017-12-20 15:19

Qurucular gizli bir dönüşüm əlavə edirlər. Bu örtük çevrilməni maneə törətmək üçün bir konstruktoru açıq bir parametr ilə elan etməlisiniz.

C ++ 11 də, "operator növü ()" sözünü http://en.cppreference.com/w/cpp/> sözü ilə də təyin edə bilərsiniz . Bu dəqiqləşdirmə ilə, operatora açıq çevrilmə və birbaşa obyektin başlanğıcından istifadə edə bilərsiniz.

PS İstifadəçi müəyyən edilmiş dönüşümlər USER (qurucular və tip çevirmə operatorları vasitəsilə) istifadə edərkən, örtülü dönüşümlərin yalnız bir səviyyəsinə icazə verilir. Ancaq bu dönüşümleri digər dil dönüşümleriyle birleştirebilirsiniz.

  • (int üçün int, ikiqat üzmək);
  • standart dönüşümlər (int cüt);
  • obyekt sinyallerini baz sinifinə çevirmək və boşluq *;
4
23 янв. Cavab bruziuz Jan 23 tərəfindən verilir 2015-01-23 12:26 '15 at 12:26 pm 2015-01-23 12:26

yazıları ilə bağlı digər suallar və ya sual verin