继承如何实际工作?
这个问题在这里已经有了答案:
第一个要点是你是对的。 派生类对象有一个称为“基类子对象”的区域。 因此,派生类对象包含一个基类子对象,其方式与包含任何非静态数据成员的成员子对象的方式完全相同。 (尽管这并不总是如此,因为编译器试图优化事物,并且最终的对象可能没有为非常简单的示例明确区分成员变量)。
第二点你错了。 它们都指向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
,但不是在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
,并且将不得不依赖A
public
或protected
成员如果它想与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()
因为b1
是B
类型的。 ( 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