为什么派生类的大小包括基类的私有成员?

时间:2011-07-04 07:47:13

标签: c++ inheritance

我有以下代码:

class A {
  private:
    int i;
 };

class B : public A {
 private:
  int j;
 };

当我检查sizeof(B)时,它似乎是sizeof(base) + sizeof(derived)。但是,我对继承的理解是基类的private成员不会被继承。为什么它们会包含在sizeof(B)的结果中?

7 个答案:

答案 0 :(得分:8)

所有成员变量都是继承的。 private protected public修饰符只会改变访问到那些变量的人

答案 1 :(得分:5)

你误解了private的作用。在您的代码段中,它只会阻止A的非成员和非朋友访问i。它只是一个访问控制修饰符。 B的实例将包含A的数据成员,即使B不会(直接)访问它。

这个比喻表明这确实有意义:

class Human
{
protected:
    void UseCognitivePowers() { brain.Process(); }
private:
    Brain brain;
    // ...
};

class StackOverflowUserInSilico : public Human
{
private:
    void AnswerStackOverflowQuestion(int questionId)
    {
        // ...
        // magic occurs here
        // ...
        UseCognitivePowers();
    }
};

即使brain上的Human是私有的,StackOverflowUserInSilico也会Brain,因为StackOverflowUserInSilico来自Human。这是必需的,否则UseCognitivePowers()函数将无效,即使StackOverflowUserInSilicoHuman继承了该方法。

当然Human的子类是否会实际利用UseCognitivePowers()类提供给它们的Human方法是完全不同的事情。

答案 2 :(得分:4)

您要么误解sizeof,要么误解C ++对象的布局(在内存中)。

出于性能原因(为了避免间接成本),编译器通常会使用Composition实现Derivation:

// A
+---+
| i |
+---+

// B
+---+---+
| A | j |
+---+---+

请注意,如果privateB无法查看A,即使它包含它。

sizeof运算符将返回B的大小,包括必要的填充(用于校正校正),如果有的话。

如果您想了解更多信息,我衷心建议 Stanley A. Lippman Inside the C++ Object Model。虽然编译器依赖,但许多编译器确实使用相同的基本原理。

答案 3 :(得分:3)

它是继承的 - 派生类对象将包含它,但派生类的成员函数无法访问它。

答案 4 :(得分:2)

在其他一些答案中已经回答了这个问题:访问说明符限制访问,但该类的成员属性仍然是继承的。

我只想提供一个理由,因为当我看到原因时,我通常会学得更好。基本上,当您从类型继承时,派生类型包含基类型的子对象,与基类可能一样小或大。 需要所有成员变量的原因是派生对象基础对象,并且可以在其上调用基本级别成员函数。即使派生类型无法访问私有成员属性,可以在该对象上调用的基本方法仍然需要访问它,因此成员必须在那里:

class base {
   int x;
public:
   base() : x(0) {}
// ...
   void printout() {
      std::cout << x << std::endl;
   }
};
class derived : public base {
// ... assume that derived does not hide `printout`
};
int main() {
   derived d;
   d.printout();  // this requires access to d.base::x
}

这只是一个简单的例子,你可以在这里说几件事来争辩说在某些情况下x可以不需要(我们正在覆盖/隐藏{派生对象中的{1}} ...但该语言仍然允许您通过限定访问隐藏/重写的成员方法,因此printout仍然可以在基础级别访问d.base::printout(),并且轮流需要printout

答案 5 :(得分:0)

访问说明符(public / private / protected)不会影响继承的“对象大小”。

答案 6 :(得分:0)

我不知道这是什么语言,但是当你继承原始对象时仍然存在。这就是为什么你仍然可以调用base.method()