为什么我的对象无法访问共同基类中另一个对象定义的受保护成员?

8
以下代码会产生编译错误:
``` 'BaseTest::_protMember' : cannot access protected member declared in class 'BaseTest' ```
为什么我不能访问类 SubTest 中已声明为 protected 的成员变量 `_protMember` 呢?
class BaseTest
{
public:
    BaseTest(){};

    BaseTest(int prot)
    {
        _protMember = prot;
    };

protected:
    int _protMember;
};

class SubTest : public BaseTest
{
    // followup question
    SubTest(const SubTest &subTest)
    {
        _protMember = subTest._protMember; // this line compiles without error
    };

    SubTest(const BaseTest &baseTest)
    {
        _protMember = baseTest._protMember; // this line produces the error
    };
};

跟进问题:

为什么在已添加的复制构造函数中,我可以访问另一个实例的受保护成员

3个回答

13
您只能从自己的基类实例访问protected成员,而不能从作为参数提供给您的实例中访问。这实际上涉及面向对象封装的概念。如果没有此限制,正在构建的对象可能会破坏baseTest&参数的不变量。
换句话说,您的SubTest可能会决定使用与另一个基于BaseTest的类(比如SubTest2 : BaseTest)使用同一成员的方式发生冲突。如果允许您的SubTest代码干扰其他对象的数据,可能会破坏SubTest2对象中的不变量,或者获得一些在预期封装中仅应暴露给SubTest2和(可选地 - 请参见下文)SubTest2派生类的值。

跟进问题: 在添加的复制构造函数中为什么可以访问另一个实例的protected成员?

SubTest(const SubTest& x);  // can access x._protMember
SubTest(const BaseTest& x);  // cannot access x._protMember
相同的洞见解释了为什么这是被允许的:拷贝构造函数获得一个SubTest&而不仅仅是从BaseTest继承的任何旧对象,而且该构造函数显然在SubTest抽象范畴内。假定SubTest编码人员熟悉所提供的预期设计/封装,那么拷贝构造函数就能够访问并强制执行其他SubTest&对象的后置条件/不变式。可能会意外地将SubTest派生对象传递到SubTest拷贝构造函数中(“切片”),但即使对于这种情况,SubTest&类也可以控制进一步派生的对象是否可能对_protMember执行任何意外操作-如果它希望“完成”对_protMember的访问并禁止任何派生类使用它,可以添加一个private using BaseTest::_protMember;语句。

谢谢您的回答。您能看一下我追加的问题吗?它包含一个可以访问另一个实例的受保护成员的函数。 - Ronald McBean
@RonaldMcBean:我已经添加了关于这个的答案。(“可以访问另一个实例的受保护成员”-但不是BaseTest而不是SubTest衍生实例-这就是难点)。 - Tony Delroy
2
这是一个很好的答案。几年前我遇到过这个问题,花了很长时间才弄清楚编译器为什么会表现出这种行为。我意识到C++的设计者在理解面向对象的责任所在方面做得非常出色。 - TooTone

6
你只能在类实例中访问protected成员。也就是说:
class SubTest : public BaseTest
{
    SubTest(const BaseTest &baseTest)
    {
        _protMember = baseTest._protMember;
     // ^^^^^^^^^^^ Is good because you are in the instance of its class
        _protMember = baseTest._protMember;
     //               ^^^^^^^^^^^^^^^^^^^^^ Produce error because you are not in the baseTest instance.              
    };

    // followup question
    SubTest(const SubTest &subTest)
    {
        _protMember = subTest._protMember;
      // Compile because access modifiers work on class level, and not on object level.
    };
};

针对后续问题的编辑:

访问修饰符是作用在类级别上,而不是对象级别上。

也就是说,同一类的两个对象可以访问彼此的私有成员。

这是我的来源:为什么我可以在复制构造函数中访问私有变量?


谢谢您的回答。您能看一下我编辑后问题的跟进吗? - Ronald McBean
看一下你代码的第五行——它不应该是“subTest._protMember”吗? - Shumail
@Shumail92 实际上不是这样的,当我第一次发布时,测试只是使用 baseTest :) 我会编辑我的帖子。 - Pierre Fourgeaud

0
通过将_protMember定义为protected,您允许派生类的对象访问它们自己的_protMember。这并不意味着所有派生类的对象都可以访问其他对象的_protMember

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