C++ 继承:为什么继承的变量和提供的变量在行为上存在差异?
例如,在这段代码中,如果注释掉了C++ 继承:为什么继承的变量和提供的变量在行为上存在差异?,c++,inheritance,C++,Inheritance,例如,在这段代码中,如果注释掉了行[a],则输出为0 inh2.cpp 我有两个问题: 在上述情况下,ab->x如何解析为10?对象的类型为类别B,因此其值应为0 为什么注释行[a]会改变代码的行为?我的推理是,x无论如何都会被继承,这将导致相同的行为 我对上述问题1的推理: ab指向类B对象的内存位置。它是一个物理对象,因为所有变量及其值都分配给内存 此对象中的变量x存储值0 当ab->x完成时,ab告诉我们对象的内存位置,然后我们去查看它,发现x是0。所以我们应该打印0 我哪里错了 是
行[a]
,则输出为0
inh2.cpp
我有两个问题:
ab->x
如何解析为10
?对象的类型为类别B
,因此其值应为0
行[a]
会改变代码的行为?我的推理是,x
无论如何都会被继承,这将导致相同的行为我对上述问题1的推理:
指向ab
对象的内存位置。它是一个物理对象,因为所有变量及其值都分配给内存类B
- 此对象中的变量
存储值x
0
- 当
完成时,ab告诉我们对象的内存位置,然后我们去查看它,发现x是0。所以我们应该打印0ab->x
B
,但您将其指定为指向a
的指针,因此它使用了在a上定义的x
(当我们处理指向a的指针时,我们不知道B
甚至存在,即使这是您分配的)A
s构造函数,然后调用B
s构造函数,该构造函数将x
(在其基类中)设置为0。此时只有一个x
,最后调用Bs构造函数B
,但您将其指定为指向a
的指针,因此它使用了在a上定义的x
(当我们处理指向a的指针时,我们不知道B
甚至存在,即使这是您分配的)A
s构造函数,然后调用B
s构造函数,该构造函数将x
(在其基类中)设置为0。此时只有一个x
,最后调用Bs构造函数进行一些小的修改:
#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;
}
这表明:
指的是ab->x
,因为A::x
属于ab
类型,并且不存在A*
变量。如果需要多态性,则必须编写一个虚拟
方法虚拟int get_x()const
隐藏B::x
。这是个坏主意,应该避免。考虑为成员变量使用一个更有意义的名称,并确定是否可以在引入新的变量之前重用基类的变量。A::x
- 强制转换到a
允许您访问B*
的成员以及B
。这应该是不言自明的a
- 进行一些小的修改:
#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;
}
这表明:
指的是ab->x
,因为A::x
属于ab
类型,并且不存在A*
变量。如果需要多态性,则必须编写一个虚拟
方法虚拟int get_x()const
隐藏B::x
。这是个坏主意,应该避免。考虑为成员变量使用一个更有意义的名称,并确定是否可以在引入新的变量之前重用基类的变量。A::x
- 强制转换到a
允许您访问B*
的成员以及B
。这应该是不言自明的a
B
,那么它不应该解析为0吗?@Lazer,谁知道?我们知道它是一个B,但是我们的指针指向一个a,这就是我们将要使用的。为了测试这一点,向B添加一个新成员,inty代码>。现在执行ab->y
。当y
不是a
的成员ab
指向类B
的对象的内存位置时,将出现编译器错误。它是一个物理对象,在这个意义上,所有变量及其值都被分配给内存并存在。此对象中的变量x
存储值0
。当ab->x
完成时,ab告诉我们对象的内存位置,然后我们去查看它,发现x是0
。所以我们应该打印0
。不知道我在这里错过了什么?[we=compiler]这里有两个变量<代码>A::x
和B::x
。如果p
是指向a
的指针,那么p->x
指的是a::x
。如果它是指向B
,则p->x
指B::x
,p->a::x
指a::x
。没有办法访问<代码>::x/c> >只给出一个指向<代码> A/<代码>的指针,因为一般不能保证有一个<代码> B<代码>。@ LaZe:不是,C++中的运行时多态性只适用于虚拟函数。不适用于变量。关于#1,在运行时,已知对象的类型为B
,那么它不应该解析为0吗?@Lazer,谁知道?我们知道它是一个B,但是我们的指针指向一个a,这就是我们将要使用的。为了测试这一点,向B添加一个新成员,inty代码>。现在执行ab->y
。当y
不是a
的成员ab
指向类B
的对象的内存位置时,将出现编译器错误。它是一个物理对象,在这个意义上,所有变量及其值都被分配给内存并存在。此对象中的变量x
存储值0
。当ab->x
完成时,ab告诉我们mem
#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