多层私有和公有继承 - 非常规访问

15
#include<iostream>
using namespace std;
class uvw;
class abc{
   private:
      int privateMember;
   protected:
    int protMember;
   public:
    int publicMember;
};

class def : private abc{
    public:
       void dummy_fn();
};

class uvw: public def{

};

void def::dummy_fn()
{
   abc x;
   def y;
   uvw z;
   cout << z.protMember << endl; // This can be accessed and doesn't give a compile-error
}

据我所知,在 def 私有继承 abc 后,protMemberpublicMemberdef 中变为私有成员。因此,现在当 uvwdef 继承时,它不应该有任何数据成员。但是我们可以通过 dummy_fn() 奇怪地访问到 z.protMember,而 z 在第一次出现时根本就没有定义变量 protMember。我哪里错了吗?

2
好问题。这可能与 dummy_fndef 的成员函数有关。但这只是猜测。 - Kiril Kirov
3
请问您能否解释一下您是Downvoter先生吗? - Mark Garcia
3
他独自漫游,从未寻找到自己的家,在互联网的踏过的树林中。他没有名字,但有一个使命。他就是那个给踩负评者。 - Yakk - Adam Nevraumont
3个回答

6
如果您尝试从自由函数中访问它,那么它将无法工作。 在这种情况下,它能够正常工作是因为dummy_fn()def的成员函数,因此它可以访问def内部的所有私有内容。 由于z是一个def,因此它也可以访问z实例内部的私有def成员。
至少这是我的猜测。 这是一个奇怪的案例。

所以,您的意思是 z 的实例也有一个 protMember 变量?我原以为由于 def 中的所有内容都是私有的,所以 z 根本不会有 'protMember' 变量。 - Ankesh Anand
2
@AnkeshAnand 访问和对象成员是不同的问题。派生类包含其基类的所有成员。你不能总是访问它们并不意味着它们不存在。 - juanchopanza
@juanchopanza 感谢您的澄清!您刚刚解决了我头脑中的一个重大疑问。 - Ankesh Anand

3
你不小心发现了C++是静态(而不是动态)类型的结果;因此,访问检查在编译时进行(而不是运行时),因此可以推断出变量的可见类型,而不是其实际动态类型(这是一种运行时属性)。
为了解开这个例子:
class Base { protected: int prot; };

class Derived: private Base { void func(); };

void Derived::func() { std::cout << prot << std::endl; }
funcDerived的成员,因此它可以访问Derived的所有数据成员,包括直接访问和通过继承可访问的数据成员:

  • Derived 直接从 Base 继承,所以可以访问Base
  • protBase中是受保护的,因此可以被任何可以访问Base的子类访问

因此,protDerived中也是可访问的(因此在Derived::func中也是可访问的)。


让我们展示一下访问路径的重要性:

class Another: private Base {};

class YetAnother: public Another { void func(); };

void YetAnother::func() { std::cout << prot << std::endl; } // ERROR (access)

在这里,虽然Base::protAnother中是可访问的,但由于Another隐藏了它继承自Base的事实,所以YetAnother无法访问Base,因此,不能访问Base::prot


让我们展示静态类型检查的效果:

class Basic { void func(); };

class More: public Basic { public: int a; };

void Basic::func() { std::cout << a << std::endl; } // ERROR (unknown)

这里,即使一个More对象将有一个a成员,在编译Basic时,我们只能依赖于Basic所知道的。而Basic并不知道a
与此形成对比的是动态语言(如Python),在该语言中,这对于类More的对象运行良好,并且对于没有a的任何人会失败(抛出AttributeError异常)。

2
私有继承只限制从类外部访问,它不限制派生类从基类中看到的内容。所以在您的情况下,def 私有继承自 abcdef 仍然可以访问 abc 的所有受保护成员。只是 def 的客户端无法访问来自 abc 的任何内容;甚至不能访问 publicMember

此外,请不要将私有继承与不继承成员或其他内容混淆。

因此,现在当 uvw 从 def 继承时,它不应该有任何数据成员。

这种说法是不正确的。uvw 同样拥有 abcdef 拥有的任何数据成员,只是它们无法从外部访问。

有关详细信息,请参见此处:http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/


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