Переменная-член имеет разные адреса в каждом методе - PullRequest
0 голосов
/ 16 января 2020

У меня есть этот код (минимальный пример):

#include <iostream>
#include <memory>

class Base {
public:
    virtual void test() = 0;

    virtual ~Base() = default;
};

template <typename T>
class Derived : public Base {
public:
    Derived() {
        foo();  // foo() gets called
    }

    void test() override {
        std::cout << "Derived test" << std::endl;
    }

    void foo() {
        static_cast<T&>(*this).bar(); // call method from child
    }
};

class Final : public Derived<Final> {
public:
    void test() override {
        std::cout << "Final::test(): " << &var << std::endl;
    }

    void bar() {
        std::cout << "Final::bar(): " <<  &var << std::endl;
    }

    int var;

};

int main() {
    std::unique_ptr<Base> a = std::make_unique<Final>(Final());
    a->test();

    return 0;
}

Теперь вот проблема. Переменная var фактически отличается в методах Final::test() и Final::bar(). Это видно из вывода кода abode:

Final::bar(): 0x7ffee5ad3988
Final::test(): 0x7fb8dbc017b8

Я считаю, что это связано с наследованием и виртуальной диспетчеризацией, но я не могу понять, почему это происходит. Не могли бы вы мне помочь, пожалуйста? Я был бы также благодарен, если бы вы могли помочь мне найти способ избавиться, если CRTP и только придерживаться наследования - теперь я не могу, так как мне нужно вызвать виртуальный метод из конструктора Derived.

1 Ответ

3 голосов
/ 16 января 2020

Я не могу понять, почему это происходит. Не могли бы вы мне помочь?

Это просто еще одно неопределенное поведение .

Когда вы создаете объект Final с оператором std::make_unique<Final>(...), иерархия конструкторы вызываются (в правильном порядке).

Final::Final() calls Derived::Derived()

Однако конструктор Derived вызывает foo(), который выполняет приведение и вызывает bar(). Когда вызывается bar(), конструктор Final еще не завершен. Это приводит к неопределенному поведению.

...