How does inheritance actually work?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #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 的私有成员变量,但它似乎没有继承,class B 的每个对象都有一个a 的副本。你能告诉我这里发生了什么事吗?主报表中的第6条将
class B 的a_p 设置为25。displayB() 函数表示class B 的a_p 的值,displayAP() 函数表示class A 的a_p 的值。但是,两者的输出都是25。你能解释一下这部分吗?
简短的回答:继承就像一个Matryoshka玩偶,每个类都完全包含它的所有基类(如果有的话)。
长答案:当一个类从一个或多个其他类继承时,派生类包含其父类,而父类又包含其父类,直到到达派生程度最低的类(没有自己父类的类)。例如,使用这个设置:
1 2 3 4 5 | class A {}; class B : public A {}; class C : public A {}; class D : public B, public C {}; class E : public D {}; |
1 2 3 4 5 6 7 8 9 10 11 12 13 | class E size(1): +--- | +--- (base class D) | | +--- (base class B) | | | +--- (base class A) | | | +--- | | +--- | | +--- (base class C) | | | +--- (base class A) | | | +--- | | +--- | +--- +--- |
注意,对于
1 2 3 4 5 | class A {}; class B : public virtual A {}; class C : public virtual A {}; class D : public B, public C {}; class E : public D {}; |
1 2 3 4 5 6 7 8 9 10 11 12 13 | class E size(16): +--- | +--- (base class D) | | +--- (base class B) 0 | | | {vbptr} | | +--- | | +--- (base class C) 8 | | | {vbptr} | | +--- | +--- +--- +--- (virtual base A) +--- |
由于每个派生类包含其整个继承层次结构,因此它还包含在其任何基类中声明的所有变量。
1 2 3 4 5 6 7 8 | 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."); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 中可见,但在C 或D 中不可见。- 遇到
protected 成员后,在整个继承层次结构中都可见。B 在A 、C 和D 中可见(但在B 中不可见,因为它不从A 继承)。E 在C 和D 中可见。 - 江户十一〔39〕人赤身露体,供世人观看。
C 和D 随处可见。
类中声明的所有成员都可以看到其包含类可见的任何成员。用你的例子,即使在调用派生类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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(); } }; |
第一个要点你是对的。派生类对象具有一个称为"基类子对象"的区域。因此,派生类对象包含基类子对象的方式与包含任何非静态数据成员的成员子对象的方式完全相同。(但情况并非总是这样,因为编译器试图优化事物,结果对象可能不会为非常简单的示例显式地区分成员变量)。
第二个要点你错了。它们都指向A::A_p(类A中包含的属性)。由于b不包含属性a_p,它将隐式指向a中的属性。
为了帮助您理解,请考虑以下代码,其中我将在中隐藏变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #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; } |
当您在main中构造b时,首先将构造对象a并将其成员设置为10。则B中的成员将设置为20。
请注意,在本例中,为了引用的成员,必须显式指定要这样做。
displayAP() function shows the value of a_p of class A.
你怎么能确定?,
Can you let me know what is happening here?
它不是一个拷贝,C++中的继承(也在所有语言中)继承了它的父成员的所有成员,不管成员是什么指定的,并且它们的访问说明符保持不变。
所以,它给你的输出是正确的,特别是在你的"主项下的前5个陈述"上。
您应该阅读关于继承的更多信息http://www.learncpp.com/cpp-tutorial/112-basic-inheritance-in-c/