无法访问派生类中基类的受保护成员

Posted

技术标签:

【中文标题】无法访问派生类中基类的受保护成员【英文标题】:Cannot access protected member of base class in derived class 【发布时间】:2012-08-29 13:16:47 【问题描述】:

我有以下代码:

struct A 
protected:
    A() 

    A* a;
;

struct B : A 
protected:
    B()  b.a = &b; 

    A b;
;

奇怪的是它不能编译。罪魁祸首是b.a = &b; 分配:GCC 和clang 都抱怨A() 受到保护,这应该不是问题,因为B 继承了A。我进入了标准的哪个黑暗角落?

【问题讨论】:

您只能访问protectedthis' base 成员(同一实例)。 thisb 不是同一个实例。 @MikeSeymour 不。 (但我承认直到最近我才想到完全相同的事情) 我确信这个问题已经被问过很多次了,但是很难找到确切的重复项。 顺便说一句,作业不是的罪魁祸首,而是其中之一。 “”可能吗? 【参考方案1】:

protected 的含义是派生类型可以访问它自己的基类 的成员,而不是任何随机对象*。在您的情况下,您关心尝试修改您无法控制的b 的成员(即您可以设置this->a,但不能设置b.a

如果您有兴趣,有一个 hack 可以让它工作,但更好的解决方案是重构代码而不依赖于 hack。例如,您可以在A 中提供一个以A* 作为参数的构造函数(此构造函数应该是公共的),然后在B 的初始化列表中对其进行初始化:

A::A( A* p ) : a(p) 
B::B() : b(&b) 

*protected 授予您访问您自己类型的任何实例或从您自己的类型派生的基本成员的权限。

【讨论】:

+1:我经常听到这样的说法“访问控制是基于每个类,而不是基于每个对象”,但似乎protected 是这个规则的一个例外? @JesseGood:不是真的,它仍然是每个班级的。我的答案可能太含糊了。您可以访问B 类型的任何对象或从B 派生的成员,但不能在A 类型的对象或从A 派生的对象中访问(不是B 请注意,您也可以使用 reinterpret_cast 欺骗编译器。丑陋,可能很危险,但是... @Macmade: reinterpret_cast 作为一般建议是危险的,因为它取决于具有标准布局的类型和对齐的对象(即仅适用于第一个基础,并非总是如此)。 static_cast 实际上可能是一个更好的选择,尽管它仍然很危险(虚拟基础),但它至少会调整基础子对象的偏移量(如果可以的话)或者......好吧,无论如何这都是未定义的行为。无论如何,reinterpret_cast 对几乎任何事情都是一个非常糟糕的建议。 “您可以访问 B 类型或从 B 派生的任何对象中的成员,但不能访问 A 类型或从 A 派生的对象(不是 B)” --- Hi David。我有一个设计,其中派生类(当然从基类派生)具有基类(组合)的多个实例。在派生类函数中,我尝试访问这些基实例的受保护成员,但出现编译错误。它不与保护的含义相冲突吗?(访问控制基于每个类)【参考方案2】:

这似乎是 C++ 语言的一大局限。你会如何解决这样的问题:

class Node

public:
 void Save();
protected:
 virtual void SaveState(int type) = 0;
;

class BinaryNode : public Node

protected:
 Node *left;
 Node *right;

 virtual void SaveState(int type) override
 
    left->SaveState(type);
    right->SaveState(type);
 
;

在此示例中,我不想让方法 SaveStateNode 层次结构之外可见。只有方法Save 应该是public

【讨论】:

如果“节点”向用户隐藏了保存过程的详细信息,那么您不应该在“BinaryNode”中影响它,因为您不知道“节点 *”的确切类型并且您不能猜测它的内部实现。在其他情况下,您需要为“保存”添加一些参数,以便从外部影响它或使您的示例更清晰【参考方案3】:

我测试的所有编译器都抱怨了几件事,特别是受保护的构造函数即使删除了赋值语句也会成为问题。

您无法访问派生自任何类型实例的protected 成员。这个问题在 11.4p1 的例子中得到了说明。

class B 
protected:
  int i;
  static int j;
;

class D1 : public B 
;

class D2 : public B 
  void mem(B*, D1*);
;

void D2::mem(B* pb, D1* p1) 
  pb->i = 1; // ill-formed
  p1->i = 2; // ill-formed
  // ...

【讨论】:

【参考方案4】:

这里实际上有两个不同的问题。

首先是该行不只是进行赋值,而是尝试初始化基类(工作正常)和成员b。要创建 b 成员,它需要构造它,作为成员它需要 public 访问它没有的构造函数。

那么分配也无法访问b 的非公共成员,因为它的类型不是B,而是类型A

请记住,protected 表示您只能通过 B 对象(或子对象)访问 A 的部分内容。

在这种情况下,请告诉我们您的真正问题,我们可以尝试帮助解决它。从同一类型继承和组合是一种设计味道。

【讨论】:

“从同一类型继承和组合是一种设计味道。”为什么?你能详细说明吗?我最近有一个设计,在派生类中,有几个基(组合)实例。在这种情况下,我需要从派生类函数中访问这些基实例的受保护成员 - 那里的编译错误。如果受保护的访问说明符是每个类(而不是每个实例),这应该被允许 - 为什么不呢? 嗨,马克。我在下面准备了一个具体问题,请您花点时间来启发我吗?(该标准没有说类似于“通过派生对象访问基类”的内容;第 237 页的第 11 条明确指出类可以使用受保护的名称派生自该类。换句话说,它在类的基础上工作,实例不会出现在图片中。)干杯。 ***.com/questions/34588930/…

以上是关于无法访问派生类中基类的受保护成员的主要内容,如果未能解决你的问题,请参考以下文章

C#:基类中的受保护方法;无法使用来自另一个类的派生类对象进行访问[重复]

派生类无法访问基类的受保护方法

静态成员函数无法访问类的受保护成员

C++ 派生模板类:访问实例的受保护成员

在派生类中使用来自虚拟基类的受保护 ctor

在派生类中无法访问受保护的成员