Подтвердить что ты не робот

"использование" ключевого слова для переменной базового класса

Я перехожу через двигатель WildMagic 5 (www.geometrictools.com), где класс Vector < наследует от класса Tuple < > , который имеет массив определенного размера с именем mTuple[] (задается параметром шаблона). Пока все хорошо, ничего особенного. Однако в классе Vector я вижу следующее:

protected:
    using Tuple<4,Real>::mTuple; 

Теперь я знаю, что ключевое слово using используется для правильного наследования перегруженных методов. В этом случае я всегда предполагал, что переменная доступна для производного класса без ввода вышеуказанного кода. Является ли это необходимым? Или это просто, чтобы сделать вещи более ясными?

4b9b3361

Ответ 1

Общее программирование немного отличается от объектно-ориентированного программирования.

Ваш mTuple является примером независимого имени. Что касается компилятора, то во время обработки определения шаблона компилятор не знает, что шаблон класса наследовал элемент данных с именем mTuple. Это может быть очевидно для вас, но это не очевидно для компилятора. На этом этапе компилятор не обращает внимания на очевидное.

Если методы шаблона производного класса хотят использовать некоторый член шаблона родительского класса, компилятор должен быть явно указан для этого. Следовательно, using.

Edit

Выше было немного немного. Важно помнить, что эти шаблоны классов не являются классами. Это шаблоны, которые в конечном итоге определяют класс. До момента, когда шаблон класса используется для определения класса, этот шаблон класса не совсем реальный. Что еще более важно, для шаблона класса, который наследуется от какого-либо другого шаблона класса, это наследование не совсем реально. Компилятор не знает об этом наследовании, если это явно не сказано об этом. Вот почему вы увидите, что шаблоны производных классов импортируют родительские члены класса через using ParentClass<Type>::member (например).

Изменить # 2

Маршалл Клайн обсуждает эту тему в своем С++ - FAQ на http://www.parashift.com/c++-faq-lite/templates.html#faq-35.19

Изменить # 3

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

Вы можете сделать все правильно (или, как вы думаете): включите все стандартные предупреждения, а затем некоторые, запустите свой код через какой-нибудь анализатор коммерческого кода, и у вас все еще может быть переносимый код.

Ответ 2

Что @David говорил, но некоторые из них не были понятны. Поэтому я считаю, что пример в порядке:

template<typename T>
struct A { int a; };

template<typename T>
struct B : A<T> {
   void f() {
     a = 0; // #1
     this->a = 0; // #2
     B::a = 0; // #3
   }
   // using A<T>::a;
};

template<>
struct A<float> { }; // surprise!

#1 Вызывает ошибку, потому что в шаблоне зависимые базовые классы не рассматриваются в результате неквалифицированного поиска. Это важное понятие в С++. Если существует глобальное a, то a будет использоваться a = 0 - член, объявленный в зависимом базовом классе, никогда не скроет этот глобальный a. Чтобы рассказать компилятору о необходимости поиска в зависимых базовых классах, вы должны определить свое имя. Итак, this->a работает отлично, как и B::a.

Если вы положили using A<T>::a, вы сообщаете компилятору объявить имя участника a в области B. Тогда a = 0 найдет a непосредственно в B. Это тоже приемлемое решение.

Ответ 3

Обычно вы можете использовать такое объявление, чтобы увеличить доступ унаследованного участника. Скажите от protected до public.

Но вы не можете использовать этот синтаксис для ограничения доступа. И вы не можете использовать его для объявленного участника private.

Так что единственный раз, когда это могло что-то сделать, - это если Vector наследуется от Tuple < > так:

class Vector4 : private Tuple<4,Real>
{ ... }

В этом случае это объявление using сделает mTuple защищенным, а не частным.

Во всех остальных случаях я ничего не сделаю.

[править]

И мое убеждение было неправильным, если речь идет о базовых классах шаблонов. См. Ответы Johannes и David.