2012-03-12 50 views
2

例如,在这一段代码,如果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 
$ 

我有两个问题:

  1. 如何ab->x决心10在上述情况下?该对象的类型为class B,因此应该值为0
  2. 为什么评论Line [a]改变了代码的行为?我的推理是x反正会继承,这应该导致相同的行为。

我给上述,Q#1推理:

  • ab点的class B对象的内存位置。从某种意义上说,它是一个物理对象,所有具有它们值的变量都被分配了内存。

  • 变量x此对象内存储值0

  • ab->x完成后,AB告诉我们对象的存储位置,我们去看看它里面找到x为0,所以我们应该打印0

我在哪里错了这里?

回答

3
  1. 是的,这是B型的,但你赋值为一个指向A,因此它使用上的一个定义的x(如当我们用指针来处理A,我们不知道B即使存在,即使这是你分配的)。

  2. 当您在施工阶段注释掉线,A的构造函数首先被调用,然后B的构造函数,这台x(在其基类)为0,只有一个x在这一点上,而Bs构造函数被称为last。

+1

关于#1,在运行时,已知该对象的类型为'B',所以它不应该解析为0? – Lazer 2012-03-12 10:36:52

+0

@拉泽尔,谁知道?我们知道它*是* B,但是我们拥有的指针是一个A,这就是将要使用的。为了测试这个,给B添加一个新成员'int y;'。现在做'ab-> y'。你会得到一个编译器错误,因为'y'不是'A'的成员。 – 2012-03-12 10:38:08

+0

'ab'指向'B类'对象的内存位置。从某种意义上说,它是一个物理对象,所有具有它们的值的变量都被分配了内存并且存在。该对象中的变量'x'存储值'0'。当'ab-> x'完成时,ab告诉我们对象的内存位置,我们去查看它,发现x是'0'。所以我们应该打印'0'。不知道我在这里错过了什么? [we = compiler] – Lazer 2012-03-12 10:41:33

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->xA::x因为ab是键入A*并且没有这样的东西作为virtual变量。如果你想要多态性,你必须写一个virtual int get_x() const方法。
  • B::x隐藏A::x。这是一个坏主意,应该避免。考虑为成员变量使用更有意义的名称,并确定在引入新变量之前是否可以重用基类的变量。
  • 通过铸造到B*,您可以访问B的会员以及A的会员。这应该是不言自明的。