89 Stimmen

Abgeleitete Vorlagenklasse Zugriff auf Mitgliederdaten der Basisklasse

Diese Frage ist eine Weiterführung der Frage, die in dieses Thema .

Verwenden Sie die folgenden Klassendefinitionen:

template <class T>
class Foo {

public:
    Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
    {
        /* do something for foo */
    }
    T Foo_T;        // either a TypeA or a TypeB - TBD
    foo_arg_t _foo_arg;
};

template <class T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {

        Foo<T>::Foo_T = T(a_arg);
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo<T>::Foo_T = T(b_arg);
    }

    void BarFunc ();

};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl;   // This doesn't work - compiler error is: error: ‘_foo_arg’ was not declared in this scope
    std::cout << Bar<T>::_foo_arg << std::endl;   // This works!
}

Wenn ich auf die Mitglieder der Basisklasse der Vorlagenklasse zugreife, scheint es, als müsste ich die Mitglieder immer explizit qualifizieren, indem ich die vorlagenartige Syntax von Bar<T>::_foo_arg . Gibt es eine Möglichkeit, dies zu vermeiden? Kann eine "using"-Anweisung/Richtlinie in einer Methode einer Vorlagenklasse zur Vereinfachung des Codes eingesetzt werden?

Editar:

Das Problem des Geltungsbereichs wird durch die Qualifizierung der Variablen mit der Syntax this-> gelöst.

98voto

sth Punkte 210180

Sie können verwenden this-> um deutlich zu machen, dass Sie sich auf ein Mitglied der Klasse beziehen:

void Bar<T>::BarFunc () {
    std::cout << this->_foo_arg << std::endl;
}

Alternativ dazu können Sie auch " using " in der Methode:

void Bar<T>::BarFunc () {
    using Bar<T>::_foo_arg;             // Might not work in g++, IIRC
    std::cout << _foo_arg << std::endl;
}

Dadurch wird dem Compiler klar, dass der Name des Mitglieds von den Parametern der Vorlage abhängt, so dass er an den richtigen Stellen nach der Definition dieses Namens sucht. Für weitere Informationen siehe auch dieser Eintrag in der C++ Faq Lite .

4 Stimmen

Der Link zur FAQ lautet sehr nützlich: Es zeigt auch, wo dieses Problem unerwünschtes Verhalten verursachen kann.

3 Stimmen

Irgendeine Idee warum ist das wahr? (die FAQ beantworten diese Frage nicht vollständig)

36voto

songyuanyao Punkte 163282

Hier ist die Basisklasse keine nicht abhängige Basisklasse (d. h. eine mit einem vollständigen Typ, der ohne Kenntnis der Vorlagenargumente bestimmt werden kann), und _foo_arg ist ein nicht abhängiger Name. Der C++-Standard besagt, dass nicht abhängige Namen nicht in abhängigen Basisklassen nachgeschlagen werden.

Um den Code zu korrigieren, reicht es aus, den Namen _foo_arg abhängig, weil abhängige Namen nur zum Zeitpunkt der Instanziierung nachgeschlagen werden können und zu diesem Zeitpunkt die genaue Basisspezialisierung, die untersucht werden muss, bekannt ist. Zum Beispiel:

// solution#1
std::cout << this->_foo_arg << std::endl;

Eine Alternative besteht darin, eine Abhängigkeit unter Verwendung eines qualifizierten Namens einzuführen:

// solution#2
std::cout << Foo<T>::_foo_arg << std::endl;

Bei dieser Lösung ist Vorsicht geboten, denn wenn der unqualifizierte, nicht abhängige Name zur Bildung eines virtuellen Funktionsaufrufs verwendet wird, hemmt die Qualifikation den Mechanismus des virtuellen Aufrufs und die Bedeutung des Programms ändert sich.

Und Sie können einen Namen aus einer abhängigen Basisklasse einmal in die abgeleitete Klasse bringen, indem Sie using :

// solution#3
template <class T>
class Bar : public Foo<T> {
public:
    ...
    void BarFunc ();
private:
    using Foo<T>::_foo_arg;
};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl;   // works
}

0voto

Daniel Earwicker Punkte 111630

Scheint in Visual C++ 2008 gut zu funktionieren. Ich habe einige Dummy-Definitionen für die Typen hinzugefügt, die Sie erwähnt haben, aber keine Quelle dafür angegeben haben. Der Rest ist genau so, wie Sie es beschrieben haben. Dann eine Hauptfunktion zum Erzwingen von BarFunc instanziiert und aufgerufen werden.

#include <iostream>

class streamable {};
std::ostream &operator<<(std::ostream &os, streamable &s) { return os; }

class foo_arg_t : public streamable {};
class a_arg_t : public streamable {};
class b_arg_t : public streamable  {};

template <class T>
class Foo {

public:
    Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
    {
        /* do something for foo */
    }
    T Foo_T;        // either a TypeA or a TypeB - TBD
    foo_arg_t _foo_arg;
};

template <class T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {

        Foo<T>::Foo_T = T(a_arg);
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo<T>::Foo_T = T(b_arg);
    }

    void BarFunc ();

};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl; 
    std::cout << Bar<T>::_foo_arg << std::endl;   
}

int main()
{
    Bar<a_arg_t> *b = new Bar<a_arg_t>(foo_arg_t(), a_arg_t());
    b->BarFunc();
}

0 Stimmen

G++ gibt eine Menge Fehler in Bezug auf die Definitionen im oberen Bereich aus. Das Problem mit dem Gültigkeitsbereich bleibt jedoch weiterhin bestehen: "error: '_foo_arg' was not declared in this scope," aufgrund des ersten Aufrufs von _foo_arg in der BarFunc()-Definition.

0 Stimmen

Meinen Sie, meine Dummy-Typ-Deklarationen geben Sie Fehler auf Gcc?

0 Stimmen

Ja, die Dummy-Typen oben, aber der Bereichsfehler bleibt auch.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X