Bir sınıfın işlev bildiriminden sonra “varsayılan” ne demektir?


221

defaultBir sınıftaki işlev bildirimlerinin yanında kullanıldığını gördüm . Bu ne işe yarıyor?

class C {
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};

26
Atama operatörü bildirimlerinde "=" işaretinden önce gelen "&" ne yapar?
dshin

6
@ dshin Bu bir üye işlevinin yeniden nitelendirilmesidir .
Kane

Yanıtlar:


249

Bu yeni bir C ++ 11 özelliğidir .

Bu, işlevin derleyici tarafından üretilen sürümünü kullanmak istediğiniz anlamına gelir, bu nedenle bir gövde belirtmeniz gerekmez.

Ayrıca kullanabilirsiniz = deletebunu belirtmek için değil derleyici otomatik olarak bu işlevi oluşturmak istiyorum.

Move yapıcıları ve move atama operatörlerinin tanıtılmasıyla, yapıcıların, yıkıcıların ve atama operatörlerinin otomatik sürümlerinin üretilmesine ilişkin kurallar oldukça karmaşık hale gelmiştir. Kuralların hatırlanması gerekmediğinden işleri kullanmak = defaultve = deletekolaylaştırır: sadece ne olmasını istediğinizi söylersiniz.


17
= deletedaha güçlüdür: Bu, aşırı yük çözünürlüğünde yer almasına rağmen, bu işlevi kullanmak yasaktır.
Deduplicator

2
Ancak, derleyici oluşturma tanımını kullanmak istiyorsak, "önce yazmak ve sonra varsayılana atamak" yerine bu işlevi yazmayı atlamamalıyız?
Mayank Jindal

47

Bu, derleyiciye ilgili yapıcı veya atama operatörünün varsayılan sürümünü, yani her üye için kopyalama veya taşıma eylemini gerçekleştiren varsayılan sürümünü oluşturmasını söyleyen yeni bir C ++ 0x özelliğidir. Bu yararlıdır, çünkü kopya oluşturucu her zaman varsayılan olarak üretilmez (örneğin, özel bir yıkıcıya sahipseniz), kopya kurucudan farklı olarak (ve atama için de aynı şekilde), ancak yazmak için önemsiz bir şey yoksa, derleyici her seferinde kendiniz heceleyerek halledin.

Ayrıca, başka bir varsayılan olmayan kurucu sağlarsanız varsayılan bir kurucu oluşturulmayacağına dikkat edin. Hala varsayılan kurucuyu da istiyorsanız, bu sözdizimini kullanarak derleyicinin bir tane oluşturmasını sağlayabilirsiniz.

Başka bir kullanım durumu olarak, bir kopya oluşturucunun dolaylı olarak oluşturulmayacağı birkaç durum vardır (örneğin, özel bir hareket kurucu sağlarsanız). Hala varsayılan sürümü istiyorsanız, bu sözdizimiyle isteyebilirsiniz.

Ayrıntılar için standardın Bölüm 12.8'ine bakın.


5
Bu sadece kurucular ve atamaları için olsa da, aynı zamanda uygulanır operator new/new[], operator delete/delete[]ve bunların aşırı yükler.
Sebastian Mach

21

C ++ 11'de yeni, buraya bakın . Bir kurucu tanımladıysanız, ancak diğerleri için varsayılanları kullanmak istiyorsanız oldukça yararlı olabilir. C ++ 11 öncesi, varsayılanlara eşdeğer olsalar bile, bir kez tanımladıktan sonra tüm kurucuları tanımlamanız gerekir.

Ayrıca bazı durumlarda kullanıcı tanım varsayılan kurucu sağlamak imkansız olduğunu unutmayın davranacağını hem alt alta sentezlenmiş derleyici aynı varsayılan ve değer başlatma. defaultbu davranışı geri almanızı sağlar.


5
ikinci paragrafla ilgili bir örnek verebilir misiniz?
John Smith

11

Bu cevaplarda bahsetmediğim başka bir kullanım durumu, bir kurucunun görünürlüğünü kolayca değiştirmenize izin vermesidir. Örneğin, bir arkadaş sınıfının kopya oluşturucuya erişmesini isteyebilirsiniz, ancak bunun herkese açık olmasını istemezsiniz.


1

C ++ 17 N4659 standart taslak

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2 "Açık olarak varsayılan işlevler":

1 Formun bir işlev tanımı:

attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;

açıkça varsayılan bir tanım olarak adlandırılır. Açıkça varsayılan olarak ayarlanmış bir işlev

  • (1.1) - özel üye fonksiyonu olmak,

  • . üye işlevinin sınıfının adı) örtük olarak bildirilmiş gibi ve

  • (1.3) - varsayılan bağımsız değişkenlere sahip değil.

2 Silinmiş olarak tanımlanmayan açıkça varsayılan bir işlev, yalnızca örtük olarak constexpr olarak bildirilmişse constexpr olarak bildirilebilir. Bir işlev ilk bildiriminde açıkça varsayılan olarak ayarlanmışsa, örtülü bildirimin olması durumunda dolaylı olarak constexpr olarak kabul edilir.

3 Açık bir şekilde varsayılan olarak ayarlanan bir işlev, örtülü bildirimle (18.4) aynı istisna belirtimini üretmeyen bir istisna belirteci ile bildirilirse,

  • (3.1) - işlev ilk bildiriminde açıkça varsayılan olarak ayarlanmışsa, silinmiş olarak tanımlanır;

  • (3.2) - aksi takdirde program kötü biçimlendirilir.

4 [Örnek:

struct S {
  constexpr S() = default;            // ill-formed: implicit S() is not constexpr
  S(int a = 0) = default;             // ill-formed: default argument
  void operator=(const S&) = default; // ill-formed: non-matching return type
  ~ S() noexcept(false) = default;    // deleted: exception specification does not match
private:
  int i;                              // OK: private copy constructor
  S(S&);
};
S::S(S&) = default;                   // OK: defines copy constructor

- son örnek]

5 Açık olarak varsayılan işlevler ve örtük olarak bildirilen işlevler topluca varsayılan işlevler olarak adlandırılır ve uygulama, bunlar için silinmiş olarak tanımlanmaları anlamına gelebilecek örtük tanımlamalar (15.1 15.4, 15.8) sağlayacaktır. Bir işlev, kullanıcı tarafından bildirilmişse ve ilk bildiriminde açıkça varsayılan olarak veya silinmemişse kullanıcı tarafından sağlanır. Kullanıcı tarafından sağlanan açıkça varsayılan bir işlev (yani, ilk bildiriminden sonra açıkça varsayılan), açıkça varsayılan olduğu noktada tanımlanır; böyle bir işlev örtük olarak silinmiş olarak tanımlanırsa, program kötü biçimlendirilir. [Not: Bir işlevi ilk bildiriminden sonra varsayılan olarak varsayılan olarak bildirmek, gelişen kod tabanına istikrarlı bir ikili arabirim sağlarken verimli yürütme ve özlü tanımlama sağlayabilir. - son not]

6 [Örnek:

struct trivial {
  trivial() = default;
  trivial(const trivial&) = default;
  trivial(trivial&&) = default;
  trivial& operator=(const trivial&) = default;
  trivial& operator=(trivial&&) = default;
  ~ trivial() = default;
};
struct nontrivial1 {
  nontrivial1();
};
nontrivial1::nontrivial1() = default;       // not first declaration

- son örnek]

O zaman soru elbette hangi fonksiyonların dolaylı olarak beyan edilebileceği ve ne zaman gerçekleştiği, ki ben de açıkladım:

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.