Путать с наследованием C ++ - PullRequest
3 голосов
/ 25 июля 2010

Я так запутался с выводом следующего кода:

#include <iostream>

using namespace std;

class Parent
{
public:
    Parent() : x(2) { }
    virtual ~Parent() { }

    void NonVirtual() { cout << "Parent::NonVirtual() x = " << x << endl; }

private:
    int x;
};

class Child : public Parent
{
public:
    Child() : x(1) { }
    virtual ~Child() { }

    void NonVirtual() { cout << "Child::NonVirtual() x = " << x << endl; }

private:
    int x;
};

int main()
{
    Child c;
    Parent* p = &c;

    c.NonVirtual();  // Output: Child::NonVirtual() x = 1
    p->NonVirtual(); // Output: Parent::NonVirtual() x = 2
    // Question: are there two x'es in the Child object c?
    //           where is x = 2 from (we have not defined any Parent object)?

    cout << sizeof(c) << endl;
    cout << sizeof(*p) << endl;

    return 0;
}

Ответы [ 2 ]

5 голосов
/ 25 июля 2010

Приведенный выше код иллюстрирует тот факт, что в C ++ только функции, отмеченные virtual, имеют переопределение .Здесь у вас есть перекрытие , а не переопределение.В переопределении и наследовании поведение основано на типе времени выполнения , который является нормальным поведением наследования, которое вы ожидаете, но если вы не объявите его виртуальным, то поведение основано исключительно на времени компиляциитип (т.е. объявленный тип).Поскольку p объявлен как тип Parent *, он использует реализацию в Parent, а c объявлен как тип Child, и поэтому он использует версию, заданную типом Child.Если вы объявили метод виртуальным, то в обоих случаях он будет искать соответствующую версию функции во время выполнения и вызовет версию, заданную в классе Child.

Я также должен добавить, что у вас есть две разные переменные x... если вы хотите разделить переменные между базовым классом и производным классом, вы должны пометить его как «защищенный» в базовом классе (хотя я бы сказал, что это обычно плохой дизайн).Переменная x, которую вы объявляете в Child, отличается от переменной в Parent.Помните, что x является приватным в Parent, и поэтому имя x не имело никакого значения в Child, пока вы не создали вторую переменную с именем x в Child.

0 голосов
/ 25 июля 2010

Здесь нечего путать. Когда вы вызываете не виртуальную функцию, какой бы тип ей ни был назначен, вызывается метод этого типа.

Здесь Parent * p и адрес дочернего элемента совпадают, но назначение относится к Parent. Таким образом, все не виртуальные методы вызывают методы родителя, а не дочерние.

Помните, что когда вы используете наследование (особенно публичное), потомок автоматически получает все методы и члены родителя. Таким образом, несмотря на то, что вы присваиваете дочерний указатель, но присваивание происходит типу родителя.

Единственное, что вам нужно убедиться, это то, что вы не удаляете здесь P, так как P и дочерний элемент C имеют общий адрес.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...