例如,在这段代码中,如果注释掉line [a]
,则输出为0.
inh2.cpp
#include<iostream>
using namespace std;
class A {
public:
int x;
A() { x = 10; }
};
class B : public A {
public:
int x; // <--------- [a]
B() { x = 0; }
};
int main() {
A* ab = new B;
cout << ab->x << endl;
}
来自gcc的结果
$ g++ inh2.cpp
$ ./a.out
10
$
我有两个问题:
ab->x
如何解析为10
?该对象的类型为class B
,因此应该为0
。Line [a]
会改变代码的行为?我的理由是,x
无论如何都会被继承,这应该导致相同的行为。我对上述问题1的推理:
ab
指向class B
对象的内存位置。在某种意义上,它是一个物理对象,所有带有值的变量都被分配了内存。
此对象中的变量x
存储值0
。
当ab->x
完成时,ab告诉我们对象的内存位置,然后我们在里面查看x是0.所以我们应该打印0。
我在哪里错了?
答案 0 :(得分:3)
是的,它的类型为B
,但是您将其指定为指向A
的指针,因此它使用在A上定义的x
(如当我们处理指向A的指针时,我们不知道B
甚至存在,即使这是你分配的内容。
当您注释掉该行时,在构建阶段,首先调用A
构造函数,然后调用B
构造函数,它设置x
(在其基类中)此时只有一个x
,最后调用Bs构造函数。
答案 1 :(得分:1)
进行一些小修改:
#include <iostream>
using namespace std;
class A {
public:
int x;
A()
:x(10)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
virtual ~A() {}
};
class B : public A {
public:
int x; // <--------- [a]
B()
:A()
,x(0)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
};
int main() {
A* ab = new B;
cout << "ab->x: " << ab->x << endl;
cout << "ab->A::x " << ab->A::x << endl;
B* b = dynamic_cast<B*>(ab);
cout << "b->x: " << b->x << endl;
cout << "b->A::x " << b->A::x << endl;
cout << "b->B::x " << b->B::x << endl;
}
这会给你:
A
10
B
0
ab->x: 10
ab->A::x 10
b->x: 0
b->A::x 10
b->B::x 0
这表明:
ab->x
引用A::x
,因为ab
的类型为A*
,并且没有virtual
变量。如果你想要多态,你将不得不写一个virtual int get_x() const
方法。B::x
隐藏A::x
。这是一个坏主意,应该避免。考虑为成员变量使用更有意义的名称,并确定在引入新变量之前是否可以重用基类的变量。B*
,您可以访问B
个成员以及A
个成员。这应该是不言自明的。