Странная проблема приведения Производная к базе в C ++ - PullRequest
4 голосов
/ 15 марта 2011

У меня есть три класса: Base, Derived (наследует от Base) и Stats (который использует Base).

Программа создает производный объект, который может быть удален и восстановлен несколько раз в течениевыполнение.Он также устанавливает объект Stats, который будет создан только один раз, но для этого необходимо вызвать функции на базе производного объекта.Поскольку производный объект может быть реконструирован, объект Stats будет нуждаться в ссылке на указатель Base, так как значение указателя может измениться.Однако когда я создаю новый Derived в main, ссылка в классе Stats не видит новый объект.

В приведенном ниже примере d и m_obj оба равны NULL, затем, когда я создаю новый производный экземпляр, m_obj по-прежнему равен NULL.Это не имеет смысла для меня.Что еще больше смущает, так это то, что если я изменю строку Derived* d = 0; на Base* d = 0;, она будет работать нормально.Есть мысли?

#include <iostream>
using namespace std;

class Base {
};

class Derived : public Base {
};

typedef Base* const base_ptr;

class Stats {
public:
    Stats(Base * const &obj) : m_obj(obj) {
        cout << "In Stats():" << endl;
        cout << "   m_obj = " << m_obj << endl;
    }

    void f() const {
        cout << "In f:" << endl;
        cout << "   m_obj = " << m_obj << endl;
    }

private:
    base_ptr &m_obj;
};

int main() {
    Derived* d = 0;
    cout << "d = " << d << endl;

    Stats s(d);

    d = new Derived();
    cout << "d (after new) = " << d << endl;

    s.f();

    return 0;
}

Ответы [ 2 ]

3 голосов
/ 15 марта 2011

Вы создаете ссылку на временный Base *, который указывает на то, на что указывал d (в данном случае NULL).Этот временный объект уничтожается после того, как строка, вызывающая конструктор, завершает выполнение.Поздравляем, вы только что вызвали неопределенное поведение!После этого может произойти все что угодно.

По сути, эта строка будет выглядеть следующим образом, если вы расширите то, что действительно происходит:

Stats s(d);

действительно:

{
    Base * const tmp = d;
    Stats s(tmp);
}

За исключениемконечно, s не исчезает, как в этом примере.

Когда d имеет тип Base *, то компилятору не нужно выполнять какое-либо преобразование типов, и поэтомуне нужно создавать временных.

3 голосов
/ 15 марта 2011

Ваш Stats фактически получает временную копию значения d. Это связано с тем, что d не относится к типу Base * const & (но может быть преобразовано в).

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