Полученный доступ класса-шаблона к данным-членам базового класса

c++ templates inheritance scope name-lookup

42727 просмотра

3 ответа

Этот вопрос является продолжением вопроса, заданного в этой теме .

Используя следующие определения классов:

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

При доступе к членам базового класса шаблонного класса кажется, что я всегда должен явно определять членов, используя синтаксис шаблонного стиля Bar<T>::_foo_arg. Есть ли способ избежать этого? Может ли оператор / директива using использовать метод класса шаблона для упрощения кода?

Редактировать:

Проблема с областью решается путем определения переменной с синтаксисом this->.

Автор: Shamster Источник Размещён: 12.11.2019 09:04

Ответы (3)


64 плюса

Решение

Вы можете использовать, this->чтобы прояснить, что вы имеете в виду члена класса:

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

В качестве альтернативы вы также можете использовать " using" в методе:

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

Это дает понять компилятору, что имя элемента зависит от параметров шаблона, поэтому он ищет определение этого имени в нужных местах. Для получения дополнительной информации также см. Эту запись в C ++ Faq Lite .

Автор: sth Размещён: 13.07.2009 05:50

23 плюса

Здесь базовый класс не является независимым базовым классом (что означает класс с полным типом, который может быть определен без знания аргументов шаблона), и _foo_argявляется независимым именем. Стандарт C ++ говорит, что независимые имена не ищутся в зависимых базовых классах.

Чтобы исправить код, достаточно сделать имя _foo_argзависимым, потому что зависимые имена можно искать только во время создания экземпляра, и в это время будет известна точная базовая специализация, которая должна быть изучена. Например:

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

Альтернатива заключается во введении зависимости с использованием квалифицированного имени:

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

Необходимо соблюдать осторожность с этим решением, потому что если неквалифицированное независимое имя используется для формирования вызова виртуальной функции, то квалификация запрещает механизм виртуального вызова, и значение программы изменяется.

И вы можете принести имя из зависимого базового класса в производный класс один раз 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
}
Автор: songyuanyao Размещён: 23.06.2014 02:33

1 плюс

Кажется, работает нормально в Visual C ++ 2008. Я добавил несколько фиктивных определений для упомянутых вами типов, но не дал источника. Остальное именно так, как вы выразились. Затем основная функция, которая BarFuncдолжна быть создана и вызвана.

#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();
}
Автор: Daniel Earwicker Размещён: 13.07.2009 05:31
Вопросы из категории :
32x32