C ++ с использованием декларации, области видимости и контроля доступа - PullRequest
10 голосов
/ 18 января 2010

Обычно объявление 'using' используется для включения в область действия некоторых функций-членов базовых классов, которые в противном случае были бы скрыты.С этой точки зрения это всего лишь механизм, позволяющий сделать доступную информацию более удобной для использования.
Однако: объявление «использование» также может использоваться для изменения ограничений доступа (не только для функций, но и для атрибутов).Например:

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 из указателя на базовый класс.Так не должно ли быть хоть какое-то предупреждение компилятора?Или было бы еще лучше запретить такое ограничение доступа производным классом?Объявление using - не единственная возможность добавить ограничения для доступа.Это также можно сделать путем переопределения функции базового класса и помещения ее в раздел с большим количеством ограничений доступа.Есть ли разумные примеры, когда действительно необходимо ограничивать доступ таким способом?Если нет, я не понимаю, почему это должно быть разрешено.

И еще: по крайней мере с g ++ один и тот же код хорошо компилируется без слова 'using'.Это означает, что для примера выше: можно написать C :: a;и C :: g;вместо использования C :: a;используя C :: g;Первый только ярлык для последнего или есть некоторые тонкие различия?

// РЕДАКТИРОВАТЬ:
поэтому из обсуждения и ответов ниже мой вывод будет:
- разрешено ограничивать ограничения доступа в производных классах с публичным наследованием
- есть полезные примеры, гдеего можно использовать
- его использование может вызвать проблемы в сочетании с шаблонами (например, производный класс больше не может быть допустимым параметром для какого-либо класса / функции шаблона, хотя он является базовым)
- более чистый языковой дизайн долженне разрешать такое использование
- компилятор может по крайней мере выдать какое-то предупреждение

Ответы [ 3 ]

5 голосов
/ 18 января 2010

Относительно вашей декларации без using: они называются «декларации доступа» и устарели. Вот текст из стандарта от 11.3/1:

Доступ члена базового класса можно изменить в производном классе, указав его квалифицированный идентификатор в объявление производного класса. Такое упоминание называется декларацией доступа. Влияние декларации доступа qualified-id; определяется как эквивалентное объявлению usingqualified-id; [Сноска: объявления доступа устарели; member using-декларации (7.3.3) предоставляют лучшие средства для выполнения тех же самых действий. В более ранних версиях языка C ++ декларации доступа были более ограничены; они были обобщены и сделаны эквивалентными using-декларациям - конечная сноска]

Я бы сказал, что чаще всего неуместно менять открытых членов на private или protected членов в производном классе, потому что это нарушит подстановку принцип: вы знаете, что базовый класс имеет некоторые функции, и если вы приведете к производному классу, то вы ожидаете, что эти функции также будут вызываться, потому что производный класс является -10 * базовым. И, как вы уже упоминали, этот инвариант в любом случае уже применяется языком, позволяющим преобразовать (который работает неявно!) В ссылку на базовый класс, или квалифицировать имя функции, а затем вызывать (тогда общедоступную) функцию.

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

3 голосов
/ 18 января 2010

Несмотря на то, что объявление об использовании, которое вы показали, действительно предоставляет механизм для изменения уровня доступа (но только вниз), это не основное использование его в таком контексте. Используемый контекст в первую очередь предназначен для предоставления доступа к функциям, которые в противном случае были бы скрыты от базового класса из-за языковой механики. Э.Г.

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
};
0 голосов
/ 18 января 2010

Декларация

using C::a

переносит "a" в локальную область именования, чтобы впоследствии вы могли использовать "a" для ссылки на "C :: a"; с тех пор «C :: a» и «a» взаимозаменяемы, если вы не объявляете локальную переменную с именем «a».

Декларация не меняет прав доступа; Вы можете получить доступ к «a» в подклассе только потому, что «a» не является частным.

...