Soru Varsayılan sınıf kurucusunu silmenin amacı nedir?


CPP sınavıma hazırlanıyorum ve şu sorulardan biri: Varsayılan sınıf kurucuyu silebilir misiniz ve eğer öyleyse, bunun nedeni ne olurdu? Tamam, belli ki bunu yapabilirsin:

class MyClass 
{ 
  public: 
    MyClass() = delete; 
};

ama neden anlamıyorsun anlamıyorum?


44
2018-02-07 13:06


Menşei


@DerekJohnson: Buna ne dersin? stackoverflow.com/q/13654927/27678 - AndyG
@ acraig5075 Başka bir kurucu sağlarsanız, varsayılan kurucu oluşturulmaz, bu yüzden onu silmeye gerek yoktur. - Richard Critten
@AndyG dürüstçe bunu okuduğunuzda, bu sorulara cevap vermez. Birinin yorumundan: “Gerçekten, bu sorunun ana soruyu nasıl yanıtladığını anlamıyorum. Başlıktaki soru ve OP'nin mesajdaki ilk sorusu şu oldu: Ne zaman / neden kurucuyu açıkça silmek istiyorum?” - Derek Johnson
@ acraig5075 Yorum alanındaki sorulara cevap vermemelisiniz. - pipe


Cevaplar:


Aşağıdaki sınıfı göz önünde bulundurun:

struct Foo {
    int i;
};

Bu sınıf bir topludır ve bu üç tanımdan biriyle bir örnek oluşturabilirsiniz:

int main() {
    Foo f1;     // i uninitialized
    Foo f2{};   // i initialized to zero
    Foo f3{42}; // i initialized to 42
}

Şimdi, başlatılmamış değerleri ve üretebilecekleri tanımlanmamış davranışları sevmediğinizi varsayalım. Varsayılan kurucuyu silebilirsiniz Foo:

struct Foo {
    Foo() = delete;
    int i;
};

Foo hala bir topluluğudur, ancak sadece son iki tanım geçerlidir - ilki bir derleme zamanı hatasıdır.


69
2018-02-07 13:17



Ya da yerine, sadece struct Foo { int i = 0; };. - T.C.
@ T.Ç. Doğru, ama bu örneğin minimal olduğunu, bu kullanışlı gelebilir daha ayrıntılı durumlar olabilir ki karşı noktayı yükseltmek. Yine de kendimle bir araya gelemem. - Machinarius
@ T.Ç. Foo artık bir toplam değil; Bu, bir ihraççı değil, ama bunu açık bir şekilde açıklamak isteriz. (nota: sadece C ++ 11 ve C ++ 14 için) - YSC
@YSC Sadece C ++ 11 için demek istediniz. - T.C.
@ T.Ç. Ho pdfs'imde karıştırdım. Evet haklısın, sadece C ++ 11. - YSC


Varsayılan yapıcıyı silmenin birkaç nedeni vardır.

  1. Sınıf tamamen statiktir ve kullanıcıların yalnızca statik yöntemlerle / üyelerle bir sınıf oluşturmasını istemezsiniz. Böyle bir sınıfın bir örneği, fabrika tasarım modelini yeni sınıflar oluşturmak için yalnızca statik yöntemler kullanarak uygulayan bir örnek olabilir.
  2. Sınıfın varsayılan bir kurucuya sahip olması mantıklı olmaz (Parametreler gerektirdiğinden / Sınıf için anlamlı olabilecek varsayılan değerler yoktur). Bu durumda = delete @HolyBlackCat dediği gibi bir stil şey, ama müşteri kodunu söyleyerek niyetinizi açıklığa kavuşturuyor bir tek Parametreleri ile yapıcıyı çağırın.
  3. Bir toplu sınıf için başlatılmamış veri istemezsiniz.

İkinci ifade açık değilse, aşağıdaki örneği göz önünde bulundurun:

class A
{
public:
   //A() = delete; 
   A(int, int) {};
};

Şu anda varsayılan kurucuyu aramayı denediyseniz, (GCC 7.2) gibi bir şeye benzeyen bir hata alırsınız:

hata: 'A :: A ()' öğesine çağrı için eşleme işlevi yok

Ancak, çizgiyi = deleteSonra aşağıdakileri alırsınız:

hata: silinen fonksiyonun kullanımı 'A :: A ()'

Bu, silinen kurucuyu, diğer hataya kıyasla kullanmaya çalıştığını açıkça belli eder, ki bu biraz belirsizdir.


43
2018-02-07 13:13



İkinci durumda otomatik olarak silinir, yani = delete stil bir şey olurdu. - HolyBlackCat
@Quentin Belki sadece statik üyeleri olan bir sınıf şablonu olabilir. - aschepler
@aschepler yeterince adil. Ad alanı şablonları da güzel olurdu. - Quentin
@HolyBlackCat Hayır… olurdu bildirilmemiş, değil silindi. İnce ama bazen önemli bir ayrım. Pratik olarak, birincisini kullanma denemesi, "Aramada eşleşen kurucu yok ..." gibi bir hataya neden olurken, ikincisi "Varsayılan kurucu aramada silinir ..." gibi bir hataya neden olur (tam olarak kontrol etmek için çok tembelim) Yine de, derleyiciye bağlı olan ifadeler.) - Arne Vogel
@HolyBlackCat Silinen bir func. aşırı yük çözünürlüğüne katılır. Örneğin. ile X(const X&) kullanıcı bildirildi, hareket c'tor örtülü olarak bildirildi, ancak X(std::move(anotherX)) hala çalışır, en yakın eşleşme olarak kopya c'tor'u seçer. Fakat hareket c'toru silinirse, bu kod kötü biçimlendirilir. Ayrıca, bir variadic c'tor'unuz varsa X(Args&&...)Bu, nesne w / o argümanlarını oluşturmak için kullanılabilir, ancak silinmişse X(). referans - Arne Vogel


Birden çok varsayılan seçenek

Bir sınıfın varsayılan yapıcısını silmek, varsayılan veya başlatılmamış durum için birden fazla seçenek olduğunda iyi bir fikirdir. Örneğin, benim bir dersim olduğunu varsayalım

template<typename F>
class Polynomial;

bir alan üzerinde bir polinomu temsil eder, F. Bu durumda, polinomun varsayılan değeri için birçok seçenek vardır. Ek olarak polinomlar için kimlik, yani sıfır olabilir, ancak çarpımsal kimliğe de sahip olabilirdik. Kullanıcının, sınıfla ilgili nedenini ve nasıl kullanıldığını açıklar.


Varsayılan seçenek yok

Diğer dikkat çeken durum ise, mantıklı olabilecek birden fazla varsayılan duruma sahip olmak yerine, hiçbirimiz yoktur. Örneğin, bir çeşitli veya yüzey.

Sonra ne Manifold()? Boş bir alan, hiçbir şey, yüzey yok, mesafe ya da metrik yok. Ama sonra bunu bir manifold olarak düşünmek mantıklı değil, bir topolojik uzay gibi daha genel bir şey.

Bu durumda, varsayılan yapıcıyı da silmeyi tercih ederim.


5
2018-02-07 20:54





Bazen sınıflar somutlaştırılmayı amaçlamaz.

Şimdiye kadar değinilmemiş olan bir örnek 'özellik' sınıflarıdır. Örneğin düşünün std::char_traitsstandart, varsayılan yapıcının silinmesi gerektiğini söylememiş olsa da, varsayılan yapıcısı az kullanışlıdır çünkü sınıfın kendisi boş, tüm işlevleri statiktir ve tür takma adlarını kullanmak için örneklendirilmesi gerekmez sağlar.

Trait sınıfları genellikle yalnızca diğer sınıfları (genellikle diğer şablon sınıfları) desteklemek için kullanılırlar, bu nedenle varsayılan yapıcılarını silmek için genellikle mantıklı olabilirler - sadece yardımcı tip olduklarını ve gerçekten de bir obje.


5
2018-02-07 21:39