конструкторы, наследование, стек, куча, указатель this и segfaults в c ++ - PullRequest
0 голосов
/ 29 августа 2018

Я боролся за какой-то код, где я не знаю, как назвать его и как его решить. Я попытался свести код к следующему примеру (поэтому сам пример не имеет смысла, но он показывает проблему):

 struct MyInterface {
    virtual ~MyInterface() {

    };
    virtual void Output() = 0;
};

class A {
public:
    MyInterface *myInterface;
    A(MyInterface *myInterface) {
        std::cout << "this in A constructor: " << this << std::endl;
        this->myInterface = myInterface;
    }
    void CallA() {
        this->myInterface->Output();
    }
};

class B : public MyInterface, A {
public:
    int v;
    B(int v) : A(this) {
        std::cout << "this in B constructor: " << this << std::endl;
        this->v = v;
    }
    virtual void Output() override {
        std::cout << "Whatever" << std::endl;
    }
    void CallB() {
        std::cout << "this in CallB: " << this << std::endl;
        this->CallA();
    }
};

class Foo {
public:
    B b;
    Foo() : b(42) {
        b = B(41);  //This will make an "invalid" B:
                    //generates B on the Stack but assign the bytes to Foo.b (which is on the the heap)
                    //so b.myInterface will point to the stack
                    //after leaving this context b.other will be invalid
    }
    void Exec() {
        b.CallB();
    }
};
int main(int argc, char **args) {
    Foo *foo = new Foo();
    foo->Exec();    //Gives a segfault, because foo->b.myInterface is not valid
    return 0;
}

Сначала я подумал, что это как-то связано с наследованием и его виртуальными методами. Но я думаю, что основной проблемой является указатель this внутри конструкторов.

Итак, мои вопросы: когда строится b, указатель this в конструкторах указывает на стек. Почему не отображается указатель this на целевую память (в куче)? Конструктор копирования не называется - Почему? Как я могу назвать эту проблему?

1 Ответ

0 голосов
/ 29 августа 2018

Конструктор копирования не вызывается, потому что вы не создаете новый объект, который назначаете существующему объекту. Это вызывает оператор присваивания.

Это копия конструкции:

B b1(42); // construction
B b2(b1); // copy construction
B b3 = b1; // looks like assignment but is actually copy construction

Это задание:

B b1(42); // construction
b1 = B(43); // b1 already exists we can't copy construct, construct a new object and assign to b1

Вам необходимо переопределить оператор присваивания :

class B
{
   B& operator=(const B& other)
   {
      // fix references to this here
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...