воскресенье, 1 сентября 2013 г.

Поиск имени в шаблонных базовых классах

В классовых иерархиях поиск имен в шаблонных базовых классах не происходит.  
Есть 3 способа заставить компилятор выполнять поиск имен в шаблонных базовых классах:
1. Обращаться к именам посредством указателя this;
2. Ввести имена базовых классов с помощью using-объявления;
3. Выполнять полную квалификацию имени при обращении, но это отключает механизм динамического связывания;

В GCC поиск в шаблонных базовых классах не выполняется согласно стандарту.
В MSVC поиск в шаблонных базовых классах происходит и ошибка не выдается.

Пример:

template<typename T>
class Base
{
public:
        T value;
        Base() : value() {}
        virtual ~Base()  {}

        void f()         { cout << "Base::f\n";                    }
        virtual void v() { cout << "virtual Base::v\n";            }

        virtual void call() { cout << "Base::call\n";                      }
};

template<typename T>
class Derived : public Base<T>
{
        virtual void v() { cout << "virtual Derived::v\n"; }
public:
        // По стандарту код ф-ии call должен приводить к ошибке компиляции,
        // но в MSVC поиск в шаблонных базовых классах происходит и ошибки нет.
        virtual void call()
        {
                 cout << ">>> Derived: value == " << value << "\n"; // Не должен находить value.
                 f();                     // Не должен находить f.
                 v();
        }
};

template<typename T>
class Derived_this : public Base<T>
{
        virtual void v() { cout << "virtual Derived_this::v\n"; }
public:
        virtual void call()      //  this включает поиск.
        {
                 cout << ">>> Derived_this: value == " << this->value << "\n";
                 this->f();
                 this->v();
        }
};

template<typename T>
class Derived_using : public Base<T>
{
        // using имен базового класса делает их видимыми.
        using Base<T>::value;
        using Base<T>::f;
        using Base<T>::v;
       
public:
        virtual void v() { cout << "virtual Derived_using::v\n"; }
        virtual void call()
        {
                 cout << ">>> Derived_using: value == " << value << "\n";
                 f();
                 v();
        }
};

template<typename T>
class Derived_explicit_call : public Base<T>
{
        virtual void v() { cout << "virtual Derived_explicit_call::v\n"; }
public:
        // Явный вызов с полной квалификацией имени выполняет поиск в базовом
        // классе, но отключает динамическое связывание.
        virtual void call()
        {
                 cout << ">>> Derived_explicit_call: value == " << Base<T>::value << "\n";
                 Base<T>::f();
                 Base<T>::v();
        }
};


int main()
{
        Base<int>* pb            = new Derived<int>;
        Base<int>* pb_this                = new Derived_this<int>;
        Base<int>* pb_using      = new Derived_using<int>;
        Base<int>* pb_expl_call = new Derived_explicit_call<int>;

        pb->call();
        pb_this->call();
        pb_using->call();
        pb_expl_call->call();

        delete pb;
        delete pb_this;
        delete pb_using;
        delete pb_expl_call;
        return 0;

}

Источник: Скотт Мэйерс Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ.

По мотивам правила 43.

1 комментарий:

  1. Wynn Las Vegas casino | JamBase
    Located in the heart of the Las 용인 출장안마 Vegas Strip, this 4-star hotel and casino 고양 출장마사지 is adjacent to The Cosmopolitan. The hotel features 순천 출장샵 5 restaurants, a 통영 출장마사지 full-service 밀양 출장마사지

    ОтветитьУдалить