使用基类名称与"using"关键字可以更改访问权限吗?

5

我的朋友给我展示了以下代码

struct A {
  virtual void f() = 0;
  virtual void g() = 0;
};

struct AInternal : A {
  virtual void f() { /* ... */ }
  virtual void g() { /* ... */ }
};

他使用AInternal作为一个内部类,实现了大部分(如果不是全部)A的功能。然后他从AInternal继承,但由于他希望AInternal保持不可访问(因为它是一个实现细节),所以他继承了受保护的实现方式。他还使用了基类名称A来使其可访问(默认情况下是受保护的,因为AInternal也是受保护的)。
struct C : protected AInternal {
  using AInternal::A;
};

实际上,这个方法运行良好(但后来我们发现,它仍然保持成员函数为private - 只有基类被变为了public),但它只适用于GCC。它无法使基类A可访问。有什么想法吗?我们甚至可以让它破坏在Clang上运行的代码。

struct C : public AInternal {
protected:
  using AInternal::A;
};

C *c = 0;
A *a = c; // error on GCC!

请问有人能帮忙吗?


如果我理解正确,那么A定义了C要提供的接口。我真正不理解的是整个设置背后的想法。它使得AInternal中的公共方法在没有在A中存在的情况下无法访问,但是我们可以将这些方法设为AInternal中的私有方法,并在C中继承公共方法。 - Pixelchemist
@Pixelchemist 的想法是通过 using AInternal::A 将成员函数重新设为公共的。这个方法并没有奏效,但确实使得基类 A 可以被访问到了。 - Johannes Schaub - litb
是啊,但我不明白为什么要使用这种布局。为什么不在AInternal中将接口方法设为公共的,使用公共继承就可以了呢?"实现细节",如辅助函数或其他成员仍然可以在AInternal中设置为私有。 - Pixelchemist
@ainternal 他只想保护中间类。我想更好的方法是为AInternal类创建一个using声明。但这会失败,因为它将成为继承构造函数声明。 - Johannes Schaub - litb
1个回答

5
你只是影响了注入类名的可见性,基类子对象或其成员的访问保护不应受到影响。如果Clang或GCC允许它影响强制转换的有效性或访问基类内部,那就是他们的错误。
[class.member.lookup] 10.2/3 表明:
在声明集中,使用声明被它们指定的成员所取代,类型声明(包括注入的类名)被它们指定的类型所取代。
基类子对象在成员查找中没有名称;注入的类名有。

说到曹操,曹操就到。我在自己的代码中遇到了一个问题,错误地假设注入类型名称具有引入它的基类相同的访问限定符。结果发现,如果你真的依赖它,最好明确定义自己的盐名,或使用特征习语。 - Potatoswatter
谢谢!我之前完全不知道这些,因为基类的可见性问题而开始睡眠不好。+1 - Johannes Schaub - litb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接