Oto'yu neden özel tipte kullanabilirim?


139

Bir şekilde aşağıdaki kodun derlenip çalıştığına şaşırdım (vc2012 & gcc4.7.2)

class Foo {
    struct Bar { int i; };
public:
    Bar Baz() { return Bar(); }
};

int main() {
    Foo f;
    // Foo::Bar b = f.Baz();  // error
    auto b = f.Baz();         // ok
    std::cout << b.i;
}

Bu kodun düzgün derlenmesi doğru mu? Ve neden doğru? autoAdını (beklendiği gibi) kullanamasam da neden özel bir türde kullanabilirim?


11
Bunun f.Baz().ida iyi olduğunu gözlemleyin std::cout << typeid(f.Baz()).name(). Sınıfın dışındaki kodlar, geri Baz()alabileceğiniz tür tarafından döndürülen türü "görebilir", sadece adlandıramazsınız.
Steve Jessop

2
Ve eğer garip olduğunu düşünüyorsanız (muhtemelen bunu yaparsınız, bunu sorduğunuz gibi görürseniz) tek kişi siz değilsiniz;) Bu strateji Güvenli-Bool Deyimi gibi şeyler için çok yararlıdır .
Matthieu M.

2
Hatırlanması gereken şey private, derleyicilerin zorlamaya yardımcı olabilecek bir şekilde API'leri tanımlamak için bir kolaylık olması olduğunu düşünüyorum . BarKullanıcıların türüne erişimi önlemesi amaçlanmadığından, bir örneği döndürerek bu erişimi sunmasını hiçbir şekilde Fooengellemez . FooBar
Steve Jessop

1
"Bu kodun düzgün derlenmesi doğru mu?" Hayýr. Yapman gerek #include <iostream>. ;-)
LF

Yanıtlar:


113

İçin kurallar autoçoğunlukla şablon türü kesinti ile aynıdır. Gönderilen örnek, özel türdeki nesneleri şablon işlevlerine geçirebilmeniz için aynı nedenle çalışır:

template <typename T>
void fun(T t) {}

int main() {
    Foo f;
    fun(f.Baz());         // ok
}

Ve neden özel tipteki nesneleri şablon fonksiyonlarına aktarabiliriz? Çünkü yalnızca türün adına erişilemez. Türün kendisi hala kullanılabilir, bu yüzden onu istemci koduna geri döndürebilirsiniz.


32
Ve gizlilik olduğunu görmek adına ile ilgisi yoktur tip eklemek public: typedef Bar return_type_from_Baz;sınıfına Foosöz konusu. Artık tür, sınıfın özel bir bölümünde tanımlanmasına rağmen genel bir adla tanımlanabilir.
Steve Jessop

1
Steve'in noktada @ tekrarlamak için: erişim belirteci adı 's ile ilgisi yoktur tip ekleyerek görüldüğü gibi, private: typedef Bar return_type_from_Baz;karşı Fooolarak, gösterdi . typedeftanımlayıcıları genel ve özel tanımlayıcılara erişmek istemez.
damienh

Bu benim için bir anlam ifade etmiyor. Türün adı yalnızca gerçek tür için bir takma addır . Ben dersek ne çıkar Barya SomeDeducedType? Özel üyelere class Fooya da herhangi bir şeye ulaşmak için kullanabileceğim gibi değil .
einpoklum

107

Erişim kontrolü isimlere uygulanır . Bu örnekle standarttan karşılaştırın:

class A {
  class B { };
public:
  typedef B BB;
};

void f() {
  A::BB x; // OK, typedef name A::BB is public
  A::B y; // access error, A::B is private
}

12

Bu soru hem chill hem de R. Martinho Fernandes tarafından çok iyi cevaplandı.

Harry Potter benzetmesi ile bir soruyu cevaplama fırsatını kaçırmadım:

class Wizard
{
private:
    class LordVoldemort
    {
        void avada_kedavra()
        {
            // scary stuff
        }
    };
public:
    using HeWhoMustNotBeNamed = LordVoldemort;

    friend class Harry;
};

class Harry : Wizard
{
public:
    Wizard::LordVoldemort;
};

int main()
{
    Wizard::HeWhoMustNotBeNamed tom; // OK
    // Wizard::LordVoldemort not_allowed; // Not OK
    Harry::LordVoldemort im_not_scared; // OK
    return 0;
}

https://ideone.com/I5q7gw

Harry loophole'u hatırlattığı için Quentin'e teşekkürler.


5
friend class Harry;Orada eksik değil mi?
Quentin

@Quentin kesinlikle haklısın! friend class Dumbledore;
Tamlık için

Harry, Wizard::LordVoldemort;modern C ++ ile arayarak korkmadığını göstermez . Bunun yerine arar using Wizard::LordVoldemort;. (Dürüst olmak gerekirse, Voldemort'u kullanmak çok doğal hissettirmiyor. ;-)
LF

8

Buradaki sorun gerçekten ilgisi yok göstermektedir 98 C ++ 'dan bir örnek, diğer (iyi) cevaplara eklemek için autohiç

class Foo {
  struct Bar { int i; };
public:
  Bar Baz() { return Bar(); }
  void Qaz(Bar) {}
};

int main() {
  Foo f;
  f.Qaz(f.Baz()); // Ok
  // Foo::Bar x = f.Baz();
  // f.Qaz(x);
  // Error: error: ‘struct Foo::Bar’ is private
}

Özel türü kullanmak yasak değildir, yalnızca türü adlandırıyordu. Bu tür adsız bir geçici oluşturmak, örneğin tüm C ++ sürümlerinde uygundur.

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.