How does inheritance actually work?
This question already has an answer here:
First bullet point you are right. The derived class object, has a region called the "base class sub-object". Thus the derived class object contains a base class subobject in precisely the same way that it contains member subobjects for any non-static data members. (This is not always the case though, as compilers try to optimize things and the resulting object might not explicitly differentiate member variables for very simple examples).
Second bullet point you are wrong. They both point to A::a_p (the property contained within class A). Since B contains no property a_p it will implicitly point to the one within A.
To help your understanding consider the following code where I am shadowing a variable in 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;
}
When you construct B in main, firstly object A will be constructed and its member will be set to 10. Then the member within B will be set to 20.
Note that in this example in order to refer to the member of A you have to explicitly specify that you want to do so.
Short answer: Inheritance is like a Matryoshka doll, and every class fully contains all of its base classes (if any).
Long answer: When a class inherits from one or more other classes, the derived class contains its parent class(es), which in turn contain their parent class(es), until you reach the least-derived class(es) (the class(es) which have no parent classes of their own). So, for example, with this setup:
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
class E : public D {};
E
contains a D
, which contains a B
(which contains an A
) and a C
(which contains another A
); it looks something like this (generated with MSVC, using compiler option /d1reportSingleClassLayoutE
in an online x64 environment).
class E size(1):
+---
| +--- (base class D)
| | +--- (base class B)
| | | +--- (base class A)
| | | +---
| | +---
| | +--- (base class C)
| | | +--- (base class A)
| | | +---
| | +---
| +---
+---
Note that this analogy is slightly off for virtual
base classes, which tend to be located immediately after the most-derived class' "main body" (for lack of a better term; the memory allocated to all non- virtual
base classes and data members) in memory.
class A {};
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};
class E : public D {};
E
contains a D
, which contains a B
and a C
. E
has a single instance of A
superglued to its back.
class E size(16):
+---
| +--- (base class D)
| | +--- (base class B)
0 | | | {vbptr}
| | +---
| | +--- (base class C)
8 | | | {vbptr}
| | +---
| +---
+---
+--- (virtual base A)
+---
As each derived class contains its entire inheritance hierarchy, it also contains all variables declared in any of its base classes.
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
contains C
, which contains A
(which contains 3 int
s), B
(which contains an int
), and an int
. Neither Clang, GCC, or MSVC will emit a Size mismatch.
error. Using /d1reportSingleClassLayoutD
...
class D size(20):
+---
| +--- (base class C)
| | +--- (base class A)
0 | | | a
4 | | | b
8 | | | c
| | +---
| | +--- (base class B)
12 | | | d
| | +---
16 | | e
| +---
+---
As such, access specifiers don't actually affect what is or isn't inherited. What they do affect, however, is what's visible to the derived class.
private
members are only visible in the class where they're declared. a
is visible in A
, but not in C
or D
protected
members are visible throughout the inheritance hierarchy, after being encountered. b
is visible in A
, C
, and D
(but not in B
, since it doesn't inherit from A
). e
is visible in C
and D
. public
members are laid bare for the world to see. c
and d
are visible everywhere. All members declared in a class can see any member that is visible to their containing class. Using your example, A::displayA()
can always see A::a
, even when called on an instance of derived class B
; however, if B
declares a member displayA()
that hides A::displayA()
, then B::displayA()
won't be able to see A::a
, and would have to rely on public
or protected
members of A
if it wanted to work with 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() function shows the value of a_p of class A.
How can you be sure about that?, b1.displayAP();
isnt calling A::displayA()
but B::displayA()
because b1
is of type B
. ( B
inherited all of your A
's properties.). Even this one b1.a_p=25;
assigns B::a_p
with a value 25
.
Can you let me know what is happening here?
It's not a copy, Inheritance in C++(well in all language too) inherits all the members of its parent no matter what specifier the member is under and also their access specifier remains the same.
So, what output it gives you is correct specially on your "first 5 statements under main"
You should read more about Inheritance http://www.learncpp.com/cpp-tutorial/112-basic-inheritance-in-c/
链接地址: http://www.djcxy.com/p/78554.html上一篇: C ++中的受保护继承
下一篇: 继承如何实际工作?