Neden bu işaretçi üzerinden şablon temel sınıf üyelerine erişmek için var mı?
Eğer sınıfları aşağıda şablonlar olsaydı sadece derived
sınıfı x
edebilirdim. Ancak, aşağıdaki kod ile bengerekthis->x
kullanın. Neden?
template <typename T>
class base {
protected:
int x;
};
template <typename T>
class derived : public base<T> {
public:
int f() { return this->x; }
};
int main() {
derived<int> d;
d.f();
return 0;
}
CEVAP
Kısa cevap: x
bağımlı bir isim yapmak için, arama şablonu parametresi bilinen kadar ertelenmiş.
Bir derleyici bir şablon görünce, bazı Çek hemen, şablon parametresi görmeden gerçekleştirmek gerekiyordu. uzun cevap: Diğerleri parametresi bilinen kadar ertelenecek. İki aşamalı bir derleme deniyor ve MSVC değil ama standardın gerektirdiği ve diğer büyük Derleyiciler tarafından uygulanmaktadır. Eğer isterseniz, derleyici şablon onu görür görmez (iç ayrıştırma ağacı gösterimi çeşit), derleme ve sonrasına kadar örnekleme derleme ertelemek gerekir.
Şablon kendisi üzerinde gerçekleştirilen denetimleri, belirli örneklemesi yerine, derleyici şablon kodu dilbilgisi gidermeniz mümkün olmasını gerektirir.
Kod dilbilgisi çözmek için C (ve C), bazen bir şey bir tür olup olmadığını bilmek gerekir. Örneğin:
#if WANT_POINTER
typedef int A;
#else
int A;
#endif
static const int x = 2;
template <typename T> void foo() { A *x = 0; }
eğer Bir türü ise, bir işaretçi (etkisi küresel x
gölge dışında) bildirir. Eğer Bir nesne ise, o çarpma (ve bazı operatör yasadışı bir rvalue atama bu aşırı yüklenmesini engelleme). Eğer yanlış ise, bu hata teşhis edilmelifaz 1'destandart bir hata olduğu belirlenirşablondabazı belirli bir örnekleme değil. Bile şablondur hiç örneği, eğer bir int
yukarıdaki kodu hatalı biçimlendirilmiş olmalı ve teşhis gibi olur foo
değildi, tüm bir şablon, ama normal bir işlev.
Şimdi, standart adları olan diyordeğilşablon parametreleri bağımlı faz 1'de çözülebilir olması gerekir. A
burada bağımlı bir ad değil, aynı şey ne olursa olsun türü için T
ifade eder. Şablon bulunmak amacıyla tanımlanır daha önce tanımlanmış olmalı ve faz 1'de kontrol ettim.
T::A
muhtemelen bir tür olup olmadığını aşamada 1 bilemeyiz T. ya da değil bağlı olarak bir isim olurdu. Bu yazın sonunda olarak kullanılabilir T
bir örnekleme oldukça muhtemel bile değil henüz tanımlanmış, ve dahi olduğunu bilmiyoruz hangi tip(ler) olarak kullanılacaktır bizim şablon parametresi. Ama kötü biçimlendirilmiş şablonlar için değerli aşama 1 çeklerimizi yapmak için dilbilgisi çözmek zorundayız. Standart bağımlı isimleri derleyici typename
ile sürece kalifiye olmayan tipler varsayalım gerektiğini belirtmek için bir kural vardırtürleri ya da bazı belirli bağlamlarda kullanılır. Örneğin template <typename T> struct Foo : T::A {};
, T::A
temel sınıf olarak kullanılır ve net bir biçimde, bir tür bu yüzden. Eğer Foo
örneği ile bazı tür bir veri üyesi A
yerine bir iç içe geçmiş Bir tür, bu bir hata kodu yapıyor örnekleme (2. aşama) değil, bir hata şablonu (faz 1).
Ama bağımlı bir sınıf bir temel sınıf ile şablonu ne olacak?
template <typename T>
struct Foo : Bar<T> {
Foo() { A *x = 0; }
};
Bir bağımlı bir isim mi, değil mi? Temel sınıflar ileherhangi biradı temel sınıf içinde görünebilir. Bir bağımlı bir adı olduğunu söyleyebiliriz, ve olmayan bir tür gibi davranın. Bu istenmeyen bir etkisi olurduher isimFoo bağımlı ve dolayısıylaher türüFoo kullanılan yerleşik türleri hariç) kaliteli olması lazım. Foo içinde, sen yazmak zorundasın:
typename std::string s = "hello, world";
std::string
bağımlı bir isim, ve bu nedenle aksi belirtilmediği sürece olmayan bir türü olarak kabul olurdu çünkü. Ah!
İkinci bir sorun ile izin tercih kodu (return x;
) bile Bar
tanımlanan önce Foo
x
değil bir üye olarak, bu tanım, birisinin daha define bir uzmanlık Bar
bazı tip Baz
böyle Bar<Baz>
var bir veri üyesi x
, ve sonra oluşturmak Foo<Baz>
. Bu örnekleme, şablon 34 ** küresel döndürmek yerine veri üyesi dönecekti. Ya da tam tersi eğer temel şablon tanımı Bar
x
, onlar belirli bir uzmanlık olmadan, ve şablona bir göz için bir küresel x
dönmek Foo<Baz>
. Bu ve sahip sorun olarak sıkıntılı gibi şaşırtıcı bir karar olduğunu düşünüyorum, ama değilsessizceşaşırtıcı bir hata atma aksine şaşırtıcı.
Bu sorunları önlemek için, yürürlükte olan standart sınıf şablonları bağımlı sınıflar sadece isimleri zaten başka bir nedenden dolayı bağımlı olduğu sürece adları için aranmaz diyor. Bu bağımlı bir baz da bulunabilir diye bağımlı olmaktan her şey durur. Ayrıca görüyorsun - temel sınıfından şeyleri hak etmek ya da tespit değil bu istenmeyen etkiye sahiptir. A
bağımlı yapmak için üç ortak yolu vardır:
- -
A
sınıfusing Bar<T>::A;
şimdiBar<T>
, dolayısıyla bağımlı bir şey ifade eder. - Kullan - Yine bu noktada
Bar<T>::A *x = 0;
, 44* *kesinlikleBar<T>
. Butypename
eskiden olmadığı için çarpma, bu yüzden muhtemelen kötü bir örnek, ama örnekleme kadaroperator*(Bar<T>::A, x)
bir rvalue döndürür olup olmadığını öğrenmek için beklememiz gerekecek. Kim bilir, belki de... this->A;
işaret -A
bir üye, çok değilFoo
olmalı bu temel sınıf, yine standart diyor, bu bağımlı hale getirir.
İki aşamalı bir derleme keman ve zordur, ve kodunuzda fazladan laf kalabalığı için bazı şaşırtıcı zorunluluklar getirmektedir. Ama yerine demokrasi gibi bir şey, diğerlerinden ayrı yapmanın en kötü yolu.
Olabilir makul bir iddia, bir örnek, return x;
mantıklı değil eğer x
iç içe geçmiş bir tür temel sınıf, yabancı dil (a) demek ki bağımlı adı ve (2) sürpriz olarak olmayan bir yazın ve kodunuzu ki iş olmadan this->
. Bir ölçüde sensin kurbanın teminat hasar çözüm için bir sorun yok Uygula durumda, ama hala sorunun temel sınıf potansiyel olarak tanıtan isimler altında gölge bütünsel ya da olmaması adları düşünce vardı, ve bir küresel varlık buldu.
Sen de muhtemelen bu tartışma varsayılan olmalı aksini bağımlı isimleri (farz yazmadıkça bir şekilde belirtilen bir nesne) veya varsayılan olmalıdır daha duyarlı (std::string s = "";
, std::string
olabilir okumak gibi bir tür beri başka bir şey yapar gramer anlamda olsa bile std::string *s = 0;
belirsiz). Yine, kuralları kabul edildi tam olarak bilmiyorum. Benim tahminim gerekli olan metnin sayfa sayısı, hangi bağlamlarda bir tür ve a-tipi olmayan belirli kuralları çok stratejik karşı hafifletilebilir.
Neden Java bize bir isim dosya adından...
::push_back vector) kullanır değeri, s...
C : sınıf veri üyesi için İşaretçi...
Neden türetilmiş sınıftaki bir yöntemi...
Neden türetilmiş bir sınıfta geçersiz ...