2010-09-26 16 views
16

Jestem nowym programistą w języku C++. i używam szablonów po raz pierwszy.dziedziczenie szablonów C++

Mam klasę abstrakcyjną i inną klasę, która ją rozszerza. ale wszystkie chronionego członkowie klasy abstrakcyjnej nie są uznawane przez pozostałe klasy:

class0.h:

template<class T> 
class class0 { 

protected: 
    char p; 
public: 
    char getChar(); 
}; 

**class1.h** 
template<class T> 
class class1:public class0<T> { 
public: 
    void printChar(); 
}; 
template<class T> 
void class1<T>::printChar(){ 
    cout<< p<<endl;//p was not declared in this scope 
} 

dziękuję. świetny tydzień =)

+0

Twoje klasy bazowe wymagają publicznego wirtualnego destruktora lub chronionego/prywatnego nie-wirtualnego destruktora. – GManNickG

+0

BTW, która klasa jest abstrakcyjna w tym? – Chubsdad

Odpowiedz

26

Powodem tego jest zachowanie reguł wyszukiwania szablonów.

p nie jest wyrażeniem zależnym, ponieważ jest po prostu identyfikatorem, a nie czymś, co zależy od parametru szablonu. Oznacza to, że klasy bazowe zależne od parametru szablonu nie będą wyszukiwane w celu rozwiązania nazwy p. Aby obejść ten problem, należy użyć czegoś, co zależy od parametru szablonu. Użycie tego będzie możliwe za pomocą this->.

np.

cout << this->p << endl; 
+0

Dziękujemy! to pomogło =) miłego dnia! – yonka

+3

@yonka: Powinieneś przyjąć jego odpowiedź. – GManNickG

+0

@GMan: Nie wiem; Litb opublikował teraz odpowiedź. :-) –

2

Nie widzę błędu kompilatora w VC9. Jest jednak kilka problemów z kodem: Po pierwsze, nie musi to być klasa szablonu, jak jest obecnie napisana ... ale może po prostu uprościłeś ją dla tego pytania? Po drugie, klasa podstawowa powinna mieć wirtualny destruktor.

#include <iostream> 

using namespace std; 

class class0 { 
public: 
    virtual ~class0(){} 

protected: 
    char p; 
public: 
    char getChar(); 
}; 

class class1 : public class0 { 
public: 
    void printChar(); 
}; 

void class1::printChar(){ 
    cout << p << endl;//p was not declared in this scope 
} 

int main() { 
    class1 c; 
    c.printChar(); 
    return 1; 
} 

Ponieważ uczysz się o szablonach, proponuję nie mieszanie pojęć dziedziczenia & (szablony) podczas nauki. Zacznij od prostego przykładu jak ten ...

#include <iostream> 
#include <string> 

using namespace std; 

template <typename T> 
T add(const T& a, const T& b) { 
    return a + b; 
} 

int main() { 
    int x = 5; 
    int y = 5; 

    int z = add(x, y); 
    cout << z << endl; 

    string s1("Hello, "); 
    string s2("World!"); 

    string s3 = add(s1, s2); 
    cout << s3 << endl; 

    return 1; 
} 

Ważnym pojęciem w powyższym kodzie jest to, że pisaliśmy ONE funkcję, która wie, jak dodać liczby całkowite i ciągi (i wiele innych typów dla tej sprawy).

+4

Dlaczego klasa bazowa ma wirtualny destruktor? Szablony są często używane do implementacji parametrycznego polimorfizmu, a wirtualna delecja jest przydatna tylko dla dynamicznego polimorfizmu (i tylko wtedy, gdy delecja jest przeprowadzana polimorficznie). –

+1

Kompilator Visual Studio 2008 jest znany z tego, że nie poprawnie implementuje reguły wyszukiwania szablonów w tym przypadku. Właśnie dlatego nie widzisz błędu. –

+0

@Ben Voigt, dobry punkt, ale OP zaczyna się od szablonów i zgadywałem, że prawdopodobnie jeszcze tego nie zrozumieli. Wygląda jednak na to, że dziedziczą dziedziczenie i chyba, że ​​specjalnie szuka on polimorficznej metody kompilacji, najbezpieczniej jest uczynić podstawowy destruktor wirtualnym. – dgnorton

14

Aby nazwa być spojrzał w sposób zależny od klasy podstawowej, dwa warunki muszą być spełnione

  • To konieczne że wyszukiwanie nie jest bezwarunkowe
  • To niezbędne że nazwa jest zależne

Te zasady, jak podano w C++ 03, różnią się od rules stated by unrevised C++98, gdzie spełniają drugi punkt (tworząc imię i nazwisko zależne) było wystarczające do wyszukiwania nazw zadeklarowanych w zależnych klasach bazowych.

Nazwa zależna jest wyszukiwana w czasie tworzenia instancji, a wyszukiwanie inne niż nieukierunkowane wyszukiwanie nie ignoruje zależnych klas podstawowych. Oba te warunki muszą być spełnione, aby znaleźć nazwę zadeklarowaną w zależnej klasie bazowej, żadne z nich nie wystarcza.Aby spełnić oba warunki można stosować różne konstrukcje

this->p 
class1::p 

obie nazwy p zależne i pierwsza wersja używa dostępu członek klasy odnośnika i druga wersja używa kwalifikowana nazwa odnośnika.