Russian Qt Forum

Программирование => С/C++ => Тема начата: konstantin от Июль 06, 2011, 14:44



Название: Вопрос по использованию указателя "this"
Отправлено: konstantin от Июль 06, 2011, 14:44
Здравствуйте!

В Qt я новичок, но с C++ знаком. При рассмотрении ряда примеров программ, написанных с использованием библиотек Qt, наткнулся на один не понятный мне момент.

В программе создается класс диалогового окна, который является наследником двух других классов - класса пользовательского интерфейса и класса QDialog. В конструкторе класса-потомка вызываются 2 функции, унаследованные от двух вышеописанных класоов-предков. Одним из параметров первой функции является указатель на объект класса QWidget. Одним из параметров второй функции является указатель на объект класса QObject. При вызове этих функций обоим параметрам присваивается значения указателя this. Мне не ясен этот момент. Указатель this хранит адрес начала области памяти, в которой хранятся поля класса-потомка. В моем понимании, такая область памяти заполнена "слоями" данных классов-предков и класса-потомка. Иерархия такая:

Класс-наследник <- QDialog <- QWidget <- QObject

Поскольку конструктор класса QObject вызывается первым, то перым слоем, на который должен указывать this, являются данные-члены класса QObject.  Не понятно, каким образом, при присвоении указателю,к примеру, на объект QWidget значения указателя this (указателя на класс-наследник), обеспечивается корректный доступ по этому указателю к данным класса QWidget?

Заранее спасибо!


Название: Re: Вопрос по использованию указателя "this"
Отправлено: Пантер от Июль 06, 2011, 14:50
Ух. Два раза прочитал и не понял. :)
Вот тут почитай (http://doc.qt.nokia.com/latest/qobject.html#QObject)


Название: Re: Вопрос по использованию указателя "this"
Отправлено: konstantin от Июль 06, 2011, 14:59
Коротко, вопрос в следующем. Что будет, если указателю на класс-предок присвоить значения указателя на класс-потомок? Такой прием я видел только при использовании виртуальных функций, но здесь другой случай


Название: Re: Вопрос по использованию указателя "this"
Отправлено: Пантер от Июль 06, 2011, 15:01
Тут не имеет значения.

MainWindow::MainWindow (QWidget *parent) : QMainWindow (parent)
{
  QWidget *widget = new QWidget (this);//Теперь MainWindow является родителем widget'а
}


Название: Re: Вопрос по использованию указателя "this"
Отправлено: konstantin от Июль 06, 2011, 15:06
Я понимаю, что делать так можно) Не понимаю только, почему так можно делать.


Название: Re: Вопрос по использованию указателя "this"
Отправлено: Пантер от Июль 06, 2011, 15:08
А что тебя смущает? Все виджеты наследуются от QWidget, он же наследуется от QObject. Я все вопроса не пойму.


Название: Re: Вопрос по использованию указателя "this"
Отправлено: konstantin от Июль 06, 2011, 15:42
Меня бы ничего не смущало, если бы QWidget был в корне.

Знаешь, как работает указатель на ту же структуру?

struct str
{
int a;
int b;
char c;
};

struct str *pstruct = new struct str;

char d = str->c;

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

Теперь представим, что у нас 3 класса.

class a
{
public:
int a;
int b;
char c;
};

class b : public a
{
public:
int d;
int e;
char f;
}

class c : public b
{
public:
int g;
int h;
char i;
b *point_to_b;
}

Пусть в классе С объявили новый конструктор (я его не написал). В нем берем и присваиваем указателю point_to_b значение this. А потом делаем следующее: g = point_to_b->e;

в моем представлении, компилятор возьмет адрес, хранящийся в this, возьмет описание класса b. Выяснит, какое смещение относительно адреса, хранящегося в this надо взять, чтобы попасть на ячейку e, добавит это смещение к адресу, хранящемуся в this и по полученному результату прочитает значение и запишет его в ячейку g. На сколько я понимаю, в данном случае this будет указывать на поле a первого класса! Таким образом, мы должны записать в ячейку g не значение ячейки e, а значение ячейки b.

Уж не знаю, как еще объяснить...


Название: Re: Вопрос по использованию указателя "this"
Отправлено: Пантер от Июль 06, 2011, 15:46
У тебя мысли совершенно не в ту сторону идут. Нету никаких b *point_to_b;. При передаче в конструктор this, класс просто регистрируется в связях родитель/ребенок. Ничего потом по этому адресу не делается. Просто когда уничтожается родитель, он сначала уничтожает всех своих детей.


Название: Re: Вопрос по использованию указателя "this"
Отправлено: Пантер от Июль 06, 2011, 15:50
Вот очень упрощенное подобие механизма:
Код
C++ (Qt)
class A {
public:
 ~A () {
   foreach (A *a, vector_) {
     delete a;
   }
 }
 void addChild (A *a) {
   vector_.push_back (a);
 }
private:
 QVector <A*> vector_;
}
 
class B : public A {
 B (A *a = 0) {
   if (a) {
     a->addChild (this);
   }
 }
}
 


Название: Re: Вопрос по использованию указателя "this"
Отправлено: konstantin от Июль 06, 2011, 15:51
Просто мы говорим о разных вещах =(
Ладно, почитаю книжки по С++.

Спасибо! ;)


Название: Re: Вопрос по использованию указателя "this"
Отправлено: konstantin от Июль 06, 2011, 16:01
Все, я ответил на свой вопрос) Спасибо за терпение!


Название: Re: Вопрос по использованию указателя "this"
Отправлено: brankovic от Июль 07, 2011, 00:15
в моем представлении, компилятор возьмет адрес, хранящийся в this, возьмет описание класса b. Выяснит, какое смещение относительно адреса, хранящегося в this надо взять, чтобы попасть на ячейку e, добавит это смещение к адресу, хранящемуся в this и по полученному результату прочитает значение и запишет его в ячейку g.

правильно

На сколько я понимаю, в данном случае this будет указывать на поле a первого класса!

неправильно; дело обстоит так (для удобства a,b,c,d,e,f,g,h,i стали a_, b_ и т.д.):

Код
C++ (Qt)
c cc;
 
a *pa = &cc;
b *pb = &cc;
c *pc = &cc;
 
cc.point_to_b = pb;
 
if (true
   && (void*) pa == (void*) pb
   && (void*) pb == (void*) pc
   && (void*) pc == (void*) pa
   && sizeof (a) == sizeof (pa->a_) + sizeof (pa->b_) + sizeof (pa->c_) + 3 /*hello alignment*/
   && sizeof (a) == 12 /*hello 32 bit x86*/
   && sizeof (b) == sizeof (a) + sizeof (pb->d_) + sizeof (pb->e_) + sizeof (pb->f_) /*a + b members*/
   && sizeof (b) == 24 /*12 + 12*/
   && sizeof (c) == 40 /*24 + 16, extra 4 for point_to_b*/
   && (char *) &pc->a_ - (char *) pa == 0
   && (char *) &pc->b_ - (char *) pa == 4
   && (char *) &pc->c_ - (char *) pa == 8
   && (char *) &pc->d_ - (char *) pa == 12
   && (char *) &pc->e_ - (char *) pa == 16
   && (char *) &pc->f_ - (char *) pa == 20
   && (char *) &pc->g_ - (char *) pa == 24
   && (char *) &pc->h_ - (char *) pa == 28
   && (char *) &pc->i_ - (char *) pa == 32
   && (char *) &pc->point_to_b - (char *) pa == 36
   && (char *) pc->point_to_b - (char *) pa == 0
)
   std::cout << "thank God, C++ is fine..\n";
else
{
   std::cerr << "Alarm! something's wrong with C++!\n";
   exit (1);
}
 
 


Название: Re: Вопрос по использованию указателя "this"
Отправлено: Igors от Июль 07, 2011, 11:55
в моем представлении, компилятор возьмет адрес, хранящийся в this, возьмет описание класса b. Выяснит, какое смещение относительно адреса, хранящегося в this надо взять, чтобы попасть на ячейку e, добавит это смещение к адресу, хранящемуся в this и по полученному результату прочитает значение и запишет его в ячейку g. На сколько я понимаю, в данном случае this будет указывать на поле a первого класса! Таким образом, мы должны записать в ячейку g не значение ячейки e, а значение ячейки b.

Уж не знаю, как еще объяснить...
Да все понятно что смущает, но просто Вы перемудрили :)  Компилятору прекрасно известно что класс "с" унаследован от "b" а тот от "a". Поэтому адрес g (члена класса "c") будет вычисляться как

&g = (char *) this + offset;

где this - указатель на "a" (базовый класс)
offset - смещение g относительно (начала) базового класса

Др. словами для объектов типов "b" и "c" их this указывают на базовый типа "a"


Название: Re: Вопрос по использованию указателя "this"
Отправлено: lenny от Август 14, 2011, 09:08
Вот очень упрощенное подобие механизма:
Код
C++ (Qt)
class A {
public:
 ~A () {
   foreach (A *a, vector_) {
     delete a;
   }
 }
 void addChild (A *a) {
   vector_.push_back (a);
 }
private:
 QVector <A*> vector_;
}
 
class B : public A {
 B (A *a = 0) {
   if (a) {
     a->addChild (this);
   }
 }
}
 
Как этот паттерн называется?