ключевое слово «using» для переменной базового класса - PullRequest
13 голосов
/ 14 июня 2011

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

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

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

Ответы [ 3 ]

9 голосов
/ 14 июня 2011

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

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

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

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

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

Редактировать # 2

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

Редактировать # 3

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

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

8 голосов
/ 14 июня 2011

Что @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 вызовет ошибку, поскольку в шаблоне зависимые базовые классы не проверяются неквалифицированным поиском . Это важная концепция в C ++. Если есть глобальный a видимый, то этот a будет использоваться a = 0 - член, объявленный в зависимом базовом классе, никогда не скрывает этот глобальный a. Чтобы указать компилятору изучать зависимые базовые классы, вы должны указать свое имя. Так что this->a работает нормально, как и B::a.

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

1 голос
/ 14 июня 2011

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

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

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

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

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

Во всех других случаях, я думаю, оно ничего не даст.

[править]

И мое убеждение было неверным, когда речь шла о базовых классах.См. Ответы от Йоханнеса и Дэвида .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...