Наследование: почему существует разница в поведении между унаследованными и предоставленными переменными? - PullRequest
2 голосов
/ 12 марта 2012

Например, в этом фрагменте кода, если 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.

Где я здесь не так?

Ответы [ 2 ]

3 голосов
/ 12 марта 2012
  1. Да, это тип B, но вы назначаете его как указатель на A, и поэтому он использует x, определенный на A (как, когда мы имеем дело с указатель на A, мы не знаем, что B даже существует, хотя это то, что вы выделили).

  2. Когда вы закомментируете строку, на этапе построения сначала вызывается конструктор A s, а затем конструктор B s, который устанавливает x (в его базовом классе) на 0. Существует только один x на данный момент, и конструктор Bs называется последним.

1 голос
/ 12 марта 2012

Внесение некоторых небольших модификаций:

#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.Это должно быть само за себя.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...