当前位置: 首页 > 知识库问答 >
问题:

派生类之友的成员访问规则,其中命名类为基类

施阳夏
2023-03-14

除另有说明外,以下所有标准参考均指N4861(2020年3月布拉格后工作草案/C++20 DIS)。

如果基类是可访问的,则可以隐式地将指向派生类的指针转换为指向该基类[...]的指针。

意味着以下示例格式良好:

class N {};

class P : private N {
    friend void f();
};

void f()  { 
    P p{};
    N* n = &p; // R: OK as per [class.access.base]/5
}

因为nr(+)的可访问基类。

  • [...]
  • /5.3M作为n的成员受到保护,R出现在类n的成员或友类中,或者出现在从n派生的类p的成员中,其中M作为p的成员是公共的、私有的或受保护的,或者
  • /5.4存在一个基类b,其名称为n,可在r中访问,而m在类b中命名时,可在r中访问。

考虑到这一点,请考虑以下示例:

class N {
  protected:
    int m;
};

class P : private N {
    friend void f();
};

void f()  {
    P p{};
    (&p)->N::m = 42;  // R: #1
}

如上所述,其中#1处的命名类是n。对于不同的编译器版本和标准,Clang和GCC都接受这个示例,这意味着它可以说是格式良好的。

问题

  • 什么规则控制#1格式良好?

如上所述,#1中的命名类是n,但是[class.access.base]/5.3不应该适用,因为r是从n派生的类p的友类(/5.3只在类p的成员中提到)。[class.access.base]/5.4不应应用,因为命名类是n,这是类层次结构中的顶级类。

可以说意味着[class.access.base]仍然需要应用;特别是[class.access.base]/5.3似乎没有提到[class.protected]/1在一个(非规范的)示例中显示的“或类P的朋友”。

(+)可访问的基类

在下面的示例中:

class B { };

class N : B {
    friend void f();
};

void f()  { /* R */ }
    null

b可通过r访问,即在n的友方f中访问。

共有1个答案

须新
2023-03-14

实际上,当指定成员是命名类的受保护成员时,[class.protected#1]节是[class.access.base#5]的附加子句,而R发生在派生类的成员或友方处。
根据class.access.base#1,n的非静态受保护成员可以作为派生类p的私有成员访问。如果命名类是P,我们可以按照class.access.base#5.2访问P的友方中的成员M

m作为N的成员是私有的,而R出现在N类的成员或朋友中,或者

回到[class.protected#1],我们应该看一下下面的规则:

  1. 成员应首先是非静态成员(数据或函数
  2. 成员应该是命名类的受保护成员。

为了使附加规则适用,还应满足下列条件

条件3可能有一些混淆,但是它没有说C必须是命名类。它只是说可以在C的成员或朋友中访问该成员。

void f()  {
    P p{};
    (&p)->N::m = 42;  // R: #1
}

如果将非静态成员M更改为静态成员,则条件1为false,这意味着附加规则将不适用于表达式。

简单地说,如果满足这些条件,[class.protected#1]为[class.access.base#5.2]的后一个项目符号添加一个额外的选项(即朋友)。此外,它还限制这些成员可以按照[class.access.base#5.2]的后一个项目符号访问,当它们满足这些条件时,它们将变成不可访问的成员。

 类似资料:
  • 我创建了Angular2 Typescript项目。我有很多表格,所以我想有一个类似基本组件的东西。 这是我的基本组件: 现在有我的子组件。我想从http获取所有项目,然后将其分配给基类 知道如何从订阅方法访问基字段吗?

  • 几天前我为STS安装了Sonarint,我想问一个关于Java:S3252规则的问题(“静态”基类成员不应通过派生类型访问)。 在我的代码中,出于某种原因(我不是该公司的架构师),许多程序都使用了包含i18n密钥的接口。其中一个接口被称为,并扩展了。当我需要来自的密钥时,如果类涉及“Regie”,例如,而不是。在这种情况下,不遵守S3252规则。 在我看来,使用(孩子)有助于防止开发人员在某一天,

  • 下面是一个人为的例子:(实际代码中使用的命名方案太令人困惑) 我有一个班主任,他是第三方图书馆的一部分,不可更改。我也有一些课程延伸到父亲;比如儿子。祖父有一个类似这样的构造函数: 这个构造函数中实际发生的事情并不重要。重要的是,它所做的任何事情都必须由所有派生类完成,因此对的调用是每个派生类构造函数的第一行。这里的含义是,祖父的所有后代的构造函数,无论距离有多远,都必须始终调用super(或调用

  • 问题内容: 我在派生类中创建了基类的实例,并尝试访问受保护的成员。 我可以直接访问派生类中的受保护成员,而无需实例化基类。 基类: 同一包中的派生类- 不同包中的派生类- 当派生类也位于同一包中,而派生类位于不同包中时,如何使用基类的实例访问派生类中基类的受保护成员呢? 如果我将受保护的成员标记为“静态”,则可以使用驻留在不同包中的派生类中的基类实例来访问基类的受保护成员。 问题答案: 没错,您是

  • 派生类可以通过提供同样签名的新版本(如果签名不同,则是函数重载而不是函数重定义)重新定义基类成员函数。派生类引用该函数时会自动选择派生类中的版本。作用域运算符可用来从派生类中访问基类的该成员函数的版本。 常见编程错误 9.3 派生类中重新定义基类的成员函数时,为完成某些附加工作.派生类版本通常要调用基类中的该函数版本。不使用作用域运算符会由于派生类成员函数实际上调用了自身而引起无穷递归。这样会使系

  • 我理解您可以从派生类访问基类的成员,然而,我有一个函数需要指向我的基类作为一个整体的指针。例如: 有没有办法从派生类中获得指向这个基类的指针?