c++ - 继承实际上是如何工作的?

标签 c++ inheritance

#include<iostream>
using namespace std;

class A
{
  int a;
public:
  int a_p;
  void displayA()
  {
    cout<<"A::a "<<a<<endl;
  }
  void displayAP()
  {
    cout<<"A::a_p "<<a_p<<endl;
  }
  void get_a(int x)
  {
    a=x;
  }
};

class B:public A
{
  int b;
public:
  void displayB()
  {
    cout<<"A::a_p "<<a_p<<endl;
  }
};

int main()
{
  B b1,b2;
  b1.get_a(5);
  b2.get_a(10);

  b1.displayA();
  b2.displayA();

  cout<<"......"<<endl;

  b1.a_p=25;
  b1.displayB(); 
  b1.displayAP();
}

我需要澄清以下内容:

  • main 下的前 5 个语句给出的输出为 5,10 .虽然 a , 是class A的私有(private)成员变量不是继承的,看起来好像 class B 的每个对象有一份 a .你能告诉我这里发生了什么吗?

  • 主集中的第 6 个语句 a_pclass B到 25。displayB()函数显示 a_p 的值的 class BdisplayAP()函数显示 a_p 的值的 class A .但是,两者的输出都是 25。您能解释一下这部分吗?

最佳答案

简短回答:继承就像套娃,每个类都完全包含它的所有基类(如果有的话)。

长答案:当一个类继承自一个或多个其他类时,派生类包含其父类,父类又包含其父类,直到到达最少派生类(没有自己的父类的类)。因此,例如,使用此设置:

class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
class E : public D {};

E 包含一个 D,其中包含一个 B(其中包含一个 A)和一个 C(包含另一个A);它看起来像这样(用 MSVC 生成,在 compiler option /d1reportSingleClassLayoutE 中使用 an online x64 environment)。

class E size(1):
        +---
        | +--- (base class D)
        | | +--- (base class B)
        | | | +--- (base class A)
        | | | +---
        | | +---
        | | +--- (base class C)
        | | | +--- (base class A)
        | | | +---
        | | +---
        | +---
        +---

请注意,对于 virtual 基类,这种类比略有偏差,它们往往位于最派生类的“主体”之后(缺少更好的术语;分配的内存内存中的所有非虚拟基类和数据成员。

class A {};
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};
class E : public D {};

E 包含一个 D,后者包含一个 B 和一个 CE 有一个 A 的实例粘在它的背面。

class E size(16):
        +---
        | +--- (base class D)
        | | +--- (base class B)
 0      | | | {vbptr}
        | | +---
        | | +--- (base class C)
 8      | | | {vbptr}
        | | +---
        | +---
        +---
        +--- (virtual base A)
        +---

由于每个派生类都包含其整个继承层次结构,因此它还包含在其任何基类中声明的所有变量。

class A { private: int a; protected: int b; public: int c; };
class B { public: int d; };
class C : public A, public B { protected: int e; };
class D : public C {};

static_assert(sizeof(C) == sizeof(A) + sizeof(B) + sizeof(int), "Size mismatch.");
static_assert(sizeof(D) == sizeof(C),                           "Size mismatch.");
static_assert(sizeof(D) == sizeof(int) * 5,                     "Size mismatch.");

D包含C,其中包含A(其中包含3个int),B (其中包含一个 int)和一个 int。 Clang、GCC 或 MSVC 都不会发出 Size mismatch. 错误。使用 /d1reportSingleClassLayoutD...

class D size(20):
        +---
        | +--- (base class C)
        | | +--- (base class A)
 0      | | | a
 4      | | | b
 8      | | | c
        | | +---
        | | +--- (base class B)
12      | | | d
        | | +---
16      | | e
        | +---
        +---

因此,访问说明符实际上并不影响继承或不继承的内容。但是,它们 影响的是派生类可见的内容。

  • private 成员仅在声明它们的类中可见。 aA 中可见,但在 CD
  • 中不可见
  • protected 成员在遇到后在整个继承层次结构中都是可见的。 bACD 中可见(但在 B 中不可见) ,因为它不继承自 A)。 eCD 中可见。
  • public 成员公开展示给全世界。 cd 随处可见。

类中声明的所有成员都可以看到对其包含的类可见的任何成员。使用您的示例,即使在派生类 B 的实例上调用,A::displayA() 始终可以看到 A::a;但是,如果 B 声明了一个隐藏 A::displayA() 的成员 displayA(),则 B::displayA() 将无法看到 A::a,并且必须依赖 publicprotected 成员>A 如果它想与 A::a 一起工作。

class A {
    int a;

  public:
    void displayA() { std::cout << "A::a " << a << std::endl; }
};

class B : public A {
  public:
    // Will emit some variation on "A::a is private, you can't access it here."
    // Note that no compiler will claim that it doesn't exist.
    // void displayA() { std::cout << "A::a " << a << std::endl; }

    // This works, though, since it goes through A::displayA(), which can see A::a.
    void displayA() { return A::displayA(); }
};

关于c++ - 继承实际上是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42280613/

相关文章:

c++ - 如何确定请求了哪个编译器

c++ - Arduino Nano:使用串行输入时,通过计时器进行的A4988步进控制不稳定

ios - 两个类的 Swift 可选继承

c++ - 使用彼此继承的类的模板化类实例之间的隐式转换

c++ - 我可以使用什么在 FPGA (Virtex) : C, C++、OpenCL、MPI 上进行开发?

c++ - 取消引用对象指针的 std::vector 的每个元素

c++ - 是否可以在 C++ 中声明 operator= private 并同时由编译器合成

.net - 为什么结构不支持继承?

c++ - 基于字符串的派生类选择 - C++

javascript - JS Revealing prototype 模式中如何实现继承?