Russian Qt Forum
Ноябрь 23, 2024, 19:49 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Вопрос по использованию указателя "this"  (Прочитано 9053 раз)
konstantin
Гость
« : Июль 06, 2011, 14:44 »

Здравствуйте!

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

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

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

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

Заранее спасибо!
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Июль 06, 2011, 14:50 »

Ух. Два раза прочитал и не понял. Улыбающийся
Вот тут почитай
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
konstantin
Гость
« Ответ #2 : Июль 06, 2011, 14:59 »

Коротко, вопрос в следующем. Что будет, если указателю на класс-предок присвоить значения указателя на класс-потомок? Такой прием я видел только при использовании виртуальных функций, но здесь другой случай
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #3 : Июль 06, 2011, 15:01 »

Тут не имеет значения.

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

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
konstantin
Гость
« Ответ #4 : Июль 06, 2011, 15:06 »

Я понимаю, что делать так можно) Не понимаю только, почему так можно делать.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #5 : Июль 06, 2011, 15:08 »

А что тебя смущает? Все виджеты наследуются от QWidget, он же наследуется от QObject. Я все вопроса не пойму.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
konstantin
Гость
« Ответ #6 : Июль 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.

Уж не знаю, как еще объяснить...
« Последнее редактирование: Июль 06, 2011, 15:48 от konstantin » Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #7 : Июль 06, 2011, 15:46 »

У тебя мысли совершенно не в ту сторону идут. Нету никаких b *point_to_b;. При передаче в конструктор this, класс просто регистрируется в связях родитель/ребенок. Ничего потом по этому адресу не делается. Просто когда уничтожается родитель, он сначала уничтожает всех своих детей.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #8 : Июль 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);
   }
 }
}
 
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
konstantin
Гость
« Ответ #9 : Июль 06, 2011, 15:51 »

Просто мы говорим о разных вещах =(
Ладно, почитаю книжки по С++.

Спасибо! Подмигивающий
Записан
konstantin
Гость
« Ответ #10 : Июль 06, 2011, 16:01 »

Все, я ответил на свой вопрос) Спасибо за терпение!
Записан
brankovic
Гость
« Ответ #11 : Июль 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);
}
 
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Июль 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"
Записан
lenny
Гость
« Ответ #13 : Август 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);
   }
 }
}
 
Как этот паттерн называется?
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.234 секунд. Запросов: 23.