#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_p
的class B
到 25。displayB()
函数显示a_p
的值的class B
和displayAP()
函数显示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
和一个 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
),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
中可见,但在C
或D
中不可见
protected
成员在遇到后在整个继承层次结构中都是可见的。b
在A
、C
和D
中可见(但在B
中不可见) ,因为它不继承自A
)。e
在C
和D
中可见。public
成员公开展示给全世界。c
和d
随处可见。
类中声明的所有成员都可以看到对其包含的类可见的任何成员。使用您的示例,即使在派生类 B
的实例上调用,A::displayA()
始终可以看到 A::a
;但是,如果 B
声明了一个隐藏 A::displayA()
的成员 displayA()
,则 B::displayA()
将无法看到 A::a
,并且必须依赖 public
或 protected
的 成员>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/