11

通常,“使用”声明用于将基类的某些成员函数引入范围,否则这些成员函数将被隐藏。从这个角度来看,它只是一种使可访问信息更方便使用的机制。
但是:'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++,相同的代码在没有“使用”这个词的情况下编译得很好。这意味着对于上面的示例:可以编写 C::a; 和 C::g; 而不是使用 C::a; 使用 C::g; 第一个只是后者的捷径还是有一些细微的差别?

//编辑:
所以从下面的讨论和答案中,我的结论是:
- 允许使用公共继承限制派生类中的访问约束
- 有一些有用的例子可以使用
它 - 它的使用可能会导致与模板结合使用的问题(例如,派生类不再是某些模板类/函数的有效参数,尽管它的基础是)
- 更简洁的语言设计不应允许此类使用
- 编译器至少可以发出某种警告

4

3 回答 3

5

关于没有using: 这些被称为“访问声明”的声明,并且已被弃用。这是来自标准的文本,来自11.3/1

通过在派生类声明中提及其限定 ID,可以在派生类中更改基类成员的访问权限。这种提及称为访问声明。访问声明的效果被定义为等同于声明[脚注:不推荐使用访问声明;成员using-declarations (7.3.3) 提供了一种更好的方法来做同样的事情。在 C++ 语言的早期版本中,访问声明受到更多限制。它们被概括并等同于using-declarations - end footnote]qualified-id;usingqualified-id;

我会说,在派生类中将公共成员更改为私有成员或受保护成员通常是不好的,因为这将违反替换原则:您知道基类有一些功能,如果您强制转换为派生类,那么您期望这些函数也可以调用,因为派生类基类。就像你已经提到的那样,无论如何,这个不变量已经被允许转换(隐式工作!)到基类引用或限定函数名,然后调用(然后是公共)函数的语言强制执行。

如果你想禁止某人调用一组基础函数,那么我认为这暗示包含(或在极少数情况下,私有继承)是一个更好的主意。

于 2010-01-18T09:30:42.320 回答
3

虽然您展示的 using 声明确实提供了一种更改访问级别的机制(但只是降低),但这并不是在这种情况下的主要用途。使用上下文主要是为了允许访问由于语言机制而从基类中隐藏的函数。例如

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
};
于 2010-01-18T09:01:38.270 回答
0

宣言

using C::a

将“a”带入本地命名范围,以便您以后可以使用“a”来引用“C::a”;从那以后,只要您不声明名称为“a”的局部变量,“C::a”和“a”就可以互换。

该声明不会改变访问权限;您只能在子类中访问“a”,因为“a”不是私有的。

于 2010-01-18T08:59:40.520 回答