Странное поведение «этого» с наследованием - PullRequest
2 голосов
/ 20 октября 2011

У меня проблемы с пониманием значения this в следующем примере:

struct A {
  int i;

  void bar() {
    cout << this << endl;
  }
};

struct B : public A {
  virtual void foo() = 0;
};

struct C : public B {
  void foo() {
    printf("hello world!\n");
  }
};

int main (int argc, const char* argv[]) {
  C* c = new C; 
  cout << c << endl;
  c->bar();
  return 0;
}

Оба раза я печатаю указатель на консоль, я получаю разные значения. Я ожидал бы, что это будет то же самое, поскольку они ссылаются на один и тот же экземпляр оба раза?!

Если я удалю виртуальную функцию или int i в A, она исчезнет. Почему?

Ответы [ 2 ]

2 голосов
/ 20 октября 2011

Это оптимизация компилятора.Структура A не имеет никаких виртуальных методов, поэтому ей не нужна v-таблица.Нет смысла хранить указатель на него в объекте типа A. Что отличает расположение объектов между объектами типа A и C, поскольку C нуждается в v-таблице.Компилятор компенсирует разницу, увеличивая this перед вызовом метода A.

Добавьте произвольный виртуальный метод в A, чтобы указатели совпадали.

2 голосов
/ 20 октября 2011

Но это относится к разным вещам.

void bar() {
    cout << this << endl;
  }

Здесь this имеет тип A*. Он указывает на ту часть объекта, которая является A.

out << c << endl;

Здесь c является C* и указывает на ту часть объекта, которая является C.

Если объект A точно совпадает с объектом C, указатели совпадают. Если они этого не делают (например, когда C содержит другие члены (скрытый указатель на vtable) и, следовательно, часть 'A' смещена относительно начала более крупного объекта), указатели не обязательно совпадают.

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