Abgeleiteter Vorlagenklassenzugriff auf Elementdaten der Basisklasse

Lesezeit: 5 Minuten

Abgeleiteter Vorlagenklassenzugriff auf Elementdaten der Basisklasse
Schwindler

Diese Frage ist eine Weiterentwicklung der in diesem Thread gestellten Frage.

Verwenden der 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!
}

Beim Zugriff auf die Mitglieder der Basisklasse der Vorlagenklasse scheint es, als müsste ich die Mitglieder immer explizit qualifizieren, indem ich die Syntax im Vorlagenstil von verwende Bar<T>::_foo_arg. Gibt es eine Möglichkeit, dies zu vermeiden? Kann eine ‘using’-Anweisung/Direktive in einer Template-Klassenmethode ins Spiel kommen, um den Code zu vereinfachen?

Bearbeiten:

Das Bereichsproblem wird gelöst, indem die Variable mit this-> Syntax qualifiziert wird.

1647192609 961 Abgeleiteter Vorlagenklassenzugriff auf Elementdaten der Basisklasse
etw

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 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 Elementname von den Vorlagenparametern abhängt, sodass er an den richtigen Stellen nach der Definition dieses Namens sucht. Weitere Informationen finden Sie auch unter diesen Eintrag in den C++ Faq Lite.

  • Der Link zu den Faq ist sehr nützlich: Es zeigt auch, wo dieses Problem unsichtbar unerwünschtes Verhalten verursachen kann.

    – xtofl

    13. Juli 2009 um 19:00 Uhr

  • Irgendeine Idee warum Das ist wahr? (Die FAQ beantwortet dies nicht vollständig)

    – Katskul

    1. Oktober 2010 um 1:26 Uhr

1647192609 74 Abgeleiteter Vorlagenklassenzugriff auf Elementdaten der Basisklasse
songyuanyao

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

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

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

Eine Alternative besteht darin, eine Abhängigkeit mit einem qualifizierten Namen einzuführen:

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

Bei dieser Lösung ist Vorsicht geboten, denn wenn der unqualifizierte unabhängige Name verwendet wird, um einen virtuellen Funktionsaufruf zu bilden, verhindert die Qualifizierung den virtuellen Aufrufmechanismus und die Bedeutung des Programms ändert sich.

Und Sie können einen Namen von einer abhängigen Basisklasse in die abgeleitete Klasse einmal durchbringen 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
}

Scheint in Visual C++ 2008 gut zu funktionieren. Ich habe einige Dummy-Definitionen für die von Ihnen erwähnten Typen hinzugefügt, aber keine Quelle dafür angegeben. Der Rest ist genau so, wie du es beschreibst. Dann eine Hauptfunktion erzwingen 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();
}

  • g++ gibt viele Fehler bezüglich der Definitionen oben aus. Das Bereichsproblem bleibt jedoch weiterhin bestehen mit: „Fehler: ‘_foo_arg’ wurde in diesem Bereich nicht deklariert“, aufgrund des ersten Aufrufs von _foo_arg in der BarFunc()-Definition.

    – Schamster

    13. Juli 2009 um 17:41 Uhr

  • Meinen Sie, meine Dummy-Typ-Deklarationen geben Ihnen Fehler auf gcc?

    – Daniel Earwicker

    13. Juli 2009 um 17:51 Uhr

  • Ja, die Dummy-Typen oben, aber der Scope-Fehler bleibt auch bestehen.

    – Schamster

    13. Juli 2009 um 17:52 Uhr

  • Ich glaube, g ++ kann in Bezug auf Ihr ursprüngliches Problem richtig sein. Der IBM-Compiler hat den gleichen Wirbel gemacht, IIRC.

    – Daniel Earwicker

    13. Juli 2009 um 17:53 Uhr

  • Entschuldigung, ich hatte einen Testcode hinzugefügt – das gab mir den Fehler. Der von Ihnen gepostete Code wird kompiliert, wenn this->_foo_arg anstelle von _foo_arg in BarFunc() verwendet wird.

    – Schamster

    13. Juli 2009 um 18:02 Uhr

998520cookie-checkAbgeleiteter Vorlagenklassenzugriff auf Elementdaten der Basisklasse

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy