继承如何实际工作?

这个问题在这里已经有了答案:

  • 私人,公共和受保护遗产之间的区别15个答案

  • 第一个要点是你是对的。 派生类对象有一个称为“基类子对象”的区域。 因此,派生类对象包含一个基类子对象,其方式与包含任何非静态数据成员的成员子对象的方式完全相同。 (尽管这并不总是如此,因为编译器试图优化事物,并且最终的对象可能没有为非常简单的示例明确区分成员变量)。

    第二点你错了。 它们指向A :: a_p(属于A类的属性)。 由于B不包含属性a_p,它将隐含地指向A中的一个。

    为了帮助你理解下面的代码,我在A中隐藏一个变量:

    #include<iostream>
    
    class A {
    
    public:
        int a;
    };
    
    class B : public A {
    public:
        int a;
    
        B() = delete;
        B(int a_a, int b_a) {
            A::a = a_a;
            a = b_a;
        } 
    
        void displayA_A() {
            std::cout << "A::a: " << A::a << std::endl;
        }
    
        void displayB_A() {
            std::cout << "B::a " << B::a << std::endl;
        }
    };
    
    int main() {
        B b(10,20);
    
        b.displayA_A();
        b.displayB_A();
    
        return 0;
    }
    

    当你在主体中构造B时,首先构造对象A并将其成员设置为10.然后B内的成员将被设置为20。

    请注意,在本例中,为了引用A的成员,您必须明确指定您想要这样做。


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

    长答案:当一个类从一个或多个其他类继承时,派生类包含它的父类(es),它继而包含它们的父类(es),直到你到达最小派生类(es)(类(没有自己的父类)。 因此,例如,使用这种设置:

    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生成,在联机x64环境中使用编译器选项/d1reportSingleClassLayoutE )。

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

    请注意,对于virtual基类,这种类比稍微偏离了一点,它们倾向于位于派生最多的类“主体”之后(由于缺乏更好的术语;分配给所有非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和一个C E有一个超级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 s), 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成员只能在声明他们的类中显示。 a在可见A ,但不是在CD
  • protected成员在整个继承层次结构中都可见。 bACD可见(但不在B ,因为它不从A继承)。 eCD可见。
  • public成员被裸露给世人看。 cd在任何地方都可见。
  • 在类中声明的所有成员都可以看到任何对其包含的类可见的成员。 使用你的例子, A::displayA()总是可以看到A::a ,即使在派生类B的实例上调用时也是如此。 但是,如果B声明隐藏A::displayA()的成员displayA() ,则B::displayA()将无法看到A::a ,并且将不得不依赖A publicprotected成员如果它想与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(); }
    };
    

    displayAP()函数显示类A的a_p的值。

    你怎么能确定? b1.displayAP(); 没有调用A::displayA()而是B::displayA()因为b1B类型的。 ( B继承了你所有的A的属性)。 即使这一个b1.a_p=25; 赋值为25 B::a_p

    你能让我知道这里发生了什么吗?

    它不是副本,C ++中的继承(以及所有语言)继承其父代的所有成员,无论该成员在哪个说明符下,并且其访问说明符也保持不变。

    所以,它给你的输出是正确的,特别是你的“主要的第一个5条语句”

    您应该阅读更多有关继承的信息。http://www.learncpp.com/cpp-tutorial/112-basic-inheritance-in-c/

    链接地址: http://www.djcxy.com/p/78553.html

    上一篇: How does inheritance actually work?

    下一篇: Variable inaccessible despite class inheritance?