C ++ Использование объявления, областей объема и доступа
-
21-09-2019 - |
Вопрос
Как правило, объявление «использование» используется для введения в область некоторых функций членов базовых классов, которые в противном случае были бы скрыты. С этой точки зрения это только механизм для предоставления доступной информации более удобной в использовании.
Однако: «Использование» также может использоваться для изменения ограничений доступа (не только для функций, но и для атрибутов). Например:
class C{
public:
int a;
void g(){ cout << "C:g()\n"; }
C() : a(0){}
};
class D : public C{
private:
using C::a;
using C::g;
public:
D() { a = 1; }
};
int main(void){
D d;
cout << d.a << endl; //error: a is inaccessible
C *cp = &d;
cout << cp->a << endl; //works
d.g(); //error: g is inaccessible
cp->g(); //works
return 0;
}
Я думаю, что это ограничение доступа в полученном классе на самом деле бесполезно, потому что вы всегда можете получить доступ к g () и a из указателя на базовый класс. Так не должно быть хотя бы какого -то предупреждения компилятора? Или разве не было бы даже лучше запретить такое ограничение доступа производным классом? Использование объявления - не единственная возможность добавить ограничения для доступа. Это также может быть сделано, переопределяя функцию базового класса «размещение ее в разделе с большими ограничениями доступа. Есть ли какие -то разумные примеры, где действительно неплохо ограничить доступ таким образом? Если нет, я не понимаю, почему это должно быть разрешено.
И еще одна вещь: по крайней мере, с G ++, один и тот же код хорошо компилируется без слова «с использованием». Это означает, что для примера выше: можно написать c :: a; и c :: g; вместо использования c :: a; Использование c :: g; Является ли первый только ярлык для последнего или есть некоторые тонкие различия?
//РЕДАКТИРОВАТЬ:
Так что из обсуждения и ответов ниже моего заключения было бы:
- разрешено ограничивать ограничения доступа в полученных классах с публичным наследством
- Есть полезные примеры, где его можно использовать
- Это использование может вызвать проблему в сочетании с шаблонами (например, полученный класс не может быть допустимым параметром для некоторых шаблонов класса/функции.
- Дизайн чистого языка не должен разрешать такое использование
- Компилятор может, по крайней мере, выпустить какое -то предупреждение
Решение
Что касается вашего декларации без using
: Они называются «объявлениями доступа» и устанавливаются. Вот текст из стандарта, из 11.3/1
:
Доступ к члену базового класса может быть изменен в полученном классе, упомянув его квалифицированный идентификатор в декларации полученного класса. Такое упоминание называется декларацией доступа. Эффект объявления доступа
qualified-id
;
определяется как эквивалент декларацииusing
qualified-id
;
Сноска: Объявления доступа устарели; член Использование деклараций (7.3.3) обеспечить лучшие средства для выполнения того же. В более ранних версиях языка C ++ объявления доступа были более ограничены; они были обобщены и сделаны эквивалентны Использование деклараций - конечная сноска
Я бы сказал, что чаще всего нехорошо меняться публичный члены частный или же защищенный Участники полученного класса, потому что это нарушит принцип замены: вы знаете, что у базового класса есть некоторые функции, и если вы бросите в полученный класс, тогда вы ожидать Эти функции тоже могут быть вызываемыми, потому что производственный класс это база. И, как вы уже упоминали, этот инвариант уже применяется в любом случае языком, позволяющим конвертировать (который неявно работает!) В ссылку на базовый класс или квалификацию имени функции, а затем вызов (тогда публичная) функция.
Если вы хотите запретить кому -то, что вызывает набор функций базы, то я думаю, что это намекает на то, что сдерживание (или в редких случаях, частное наследование), является лучшей идеей.
Другие советы
В то время как использование объявления, которое вы показали, дает механизм для изменения уровня доступа (но только вниз), это не является основным его использованием в таком контексте. Использование контекста. В основном предназначен для доступа к функциям, которые в противном случае были бы затенены из базового класса из -за языковой механики. Например
class A {
public:
void A();
void B();
};
class B {
public:
using A::B;
void B(int); //This would shadow A::B if not for a using declaration
};
Декларация
using C::a
приносит «A» в локальный сферу именования, чтобы позже вы могли использовать «A», чтобы судить «c :: a»; С тех пор, как «C :: A» и «A» взаимозаменяемы, если вы не объявляете локальную переменную с именем «A».
Декларация не меняет права доступа; Вы можете получить доступ к «A» в подклассе только потому, что «A» не является частным.