简答:继承就像套娃,每个类都完全包含它的所有基类(如果有的话)。
长答案:当一个类从一个或多个其他类继承时,派生类包含其父类,而父类又包含其父类,直到您到达派生最少的类(没有自己的父类的类)。因此,例如,使用此设置:
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 生成,在 an online x64 environment 中使用 compiler option /d1reportSingleClassLayoutE)。
class E size(1):
+---
| +--- (base class D)
| | +--- (base class B)
| | | +--- (base class A)
| | | +---
| | +---
| | +--- (base class C)
| | | +--- (base class A)
| | | +---
| | +---
| +---
+---
请注意,virtual 基类的类比略有偏差,基类往往位于最派生类的“主体”之后(因为没有更好的术语;分配给所有非 @ 的内存) 987654333@ 基类和数据成员)在内存中。
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 个ints)、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 随处可见。
类中声明的所有成员都可以看到对其包含类可见的任何成员。使用您的示例,A::displayA() 始终可以看到A::a,即使在派生类B 的实例上调用时也是如此;然而,如果B 声明了一个隐藏A::displayA() 的成员displayA(),那么B::displayA() 将无法看到A::a,并且将不得不依赖public 或protected 的@987654381 成员@如果它想与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(); }
};