为什么私有成员会被继承?

4

那么基类中的private成员也存在于派生类中,但是无法在派生类中访问,对吗?
它们实际上存在于分配给派生对象的内存中吗?


2
继承是一种“是一个”关系,因此是的,基类所需的所有内存在子类中都是必需的。 - clcto
3个回答

7

它们实际上是分配给继承对象的内存吗?

是的,它们需要存在。私有成员是基类实现细节的一部分。通常情况下,如果没有它们,基类将无法运行(这也是它们存在的原因)。

将它们设置为私有只允许基类按照自己的方式创建其实现,而不向任何人公开,包括子类。


1
除了这个好答案之外,我想说的是,基本上当你有一个基类 MyBase 时,它被一些类 MyDerived 继承(无论是公共的、私有的还是受保护的),当你创建一个类型为 MyDerived 的对象时,在内存中的对象布局中,你实际上会有一个类型为 MyBase 的对象。所以简单地说:每个类型为 MyDerived 的对象都会在其内部拥有一个类型为 MyBase 的对象。 - BlackCat
@BlackCat - Re 所以简单地说:每个类型为MyDerived的对象内部都会有一个类型为MyBase的对象。 钻石继承。假设B和C都从A虚拟继承,D从B和C继承。在类D的实例中嵌入的B和C对象中至少有一个不包含"A"对象。 - David Hammen
@David:B 和 C 都将拥有一个指向公共(共享)基类 A 对象的指针。虽然它们不一定内含 A 类对象,但它们的行为就像它们拥有一样。 - Tomek

6

可以的。例如,您可以在派生类的实例中使用来自基类的公共函数来操作私有数据:

class Base { 
    int x;
public:
    Base() : x(0) {}
    void inc() { ++x; }
    void show() { std::cout << x << "\n"; }
};

class Derived : public Base { 
};

int main() { 
    Derived d;
    d.show();
    d.inc();
    d.show();
}

如果编译器正常工作,这将显示:

0
1

展示了基础对象中的数据存在于派生对象中,尽管它(直接)不可访问。

当然,在C++中几乎任何事情都有“似乎如此”的规则 - 如果编译器可以确定即使不包括基类的私有部分也可以生成程序的正确可观察行为,那么它就可以自由这样做。最明显的例子是,如果在基类中包含某些(成员函数或数据),但实际上从未使用过。


如果您将代码编译为可分发的DLL,那么如何知道特定成员函数是否未被使用? - TemplateRex
@TemplateRex:很有可能它做不到,所以在这种情况下,它很可能没有省略它的可能性。 - Jerry Coffin
我认为一旦派生类的根本问题在于它可以再次被继承,潜在的子类是一个开放集合。因此,除非将Derived标记为final,否则我认为编译器无法将 as-if 规则应用于其类布局。除此之外,未来调用者的集合也是一个开放集合。 - TemplateRex
@TemplateRex:编译器本身可能做不到,但链接器通常可以/会做到。 - Jerry Coffin

2

是的,它们是。

当派生类对象正在构造时,它所有的基类也会先被构造。

考虑以下示例:

class Base
{
 int x;

 public:
  Base(int px)
   : x(px)
  {
  }
};

class Derived : public Base
{
 int y;
public:
  Derived(int px, int py)
   : y(py), Base(px)
  {
  }
};

这个例子编译并运行成功,Base在Derived构造函数体之前被初始化(构造函数被调用)。

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