crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

3 страниц V  < 1 2 3 >  
Ответить в данную темуНачать новую тему
> Странное поведение при множественном наследовании QObject
aljeshishe
  опции профиля:
сообщение 1.12.2009, 23:06
Сообщение #11


Студент
*

Группа: Новичок
Сообщений: 12
Регистрация: 1.12.2009
Пользователь №: 1271

Спасибо сказали: 2 раз(а)




Репутация:   0  


Цитата(BRE @ 1.12.2009, 21:30) *
Цитата(Litkevich Yuriy @ 1.12.2009, 21:03) *
BRE, ничего не изменилось

Хм, сделал наследование каком к верху, т.е. "А" первый, тогда получаю единичку.

Тут имеет значение порядок наследования.
В первом случае в памяти имеем (объект класса B ):
int a;
<данные QObject>
int b;

Во втором случае:
<данные QObject>
int a;
int b;

Т.е. смещение переменной a будет разным и компилятор не может правильно рассчитать смещение при обычном привидении типа (void* -> A*).
А вот если указатель сначала привести к B*, а потом к A*, то все будет нормально.

Провел несколько экспериментов с порядком наследования, скажите правильно я понял, что:
1. Сначала в памяти идут виртуальные базовые классы в порядке наследования
2. затем невиртуальные классы в порядке наследования
3. в конце идет дочерний класс

И еще вопросик, как располагается в памяти виртуальное наследование ?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 1.12.2009, 23:20
Сообщение #12


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Не совсем так, получается примерно так, когда ты создаешь объект класса B создаются аргументы данного класса в такой последовательности:
vpointer *p; // создается неявно компилятором
int a;
int b;
после чего, когда ты приводишь объект класса B к классу A, то аргументу класса A a присваивается значение p (что тот, что другой 4 байта), так как если создать объект класса А, то создается только:
int a;
Если же в классе А добавить ключевое слова virtual деструктору, то создается таблица виртуальных методов и указатель на нее, то есть получается следующая картина:
vpointer *p;
int a;
и все приводится без проблем. :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 1.12.2009, 23:23
Сообщение #13


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Ой, не являюсь знатоком стандарта, поэтому точно сказать не могу. Может это прописано в стандарте, а может это остается на совести конкретного компилятора.
Попробуй найти эту информацию в книгах/интернете.
Если после своего исследования отпишишся здесь, думаю не только я скажу спасибо.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
frg10
  опции профиля:
сообщение 1.12.2009, 23:34
Сообщение #14


Студент
*

Группа: Участник
Сообщений: 47
Регистрация: 8.11.2009
Из: Ростов-на-Дону
Пользователь №: 1213

Спасибо сказали: 5 раз(а)




Репутация:   2  


Цитата(aljeshishe @ 1.12.2009, 19:52) *
void* p = new B;
A* a = (A*)p;

Не делайте так больше никогда. Компилятор не знает ничего о том, что находится по указателю p, поэтому не может корректно привести типы.
Вот так правильно:
    B* p = new B;
    A* a = (A*)p;
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 1.12.2009, 23:41
Сообщение #15


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(ViGOur @ 2.12.2009, 2:20) *
Если же в классе А добавить ключевое слова virtual деструктору
правильно ли понимаю, что это ключевое слово не обязательно именно для деструктора, просто нужен хотя бы один виртуальный метод. А в данном примре оказалось удобнее написать его для деструктора, чтобы не изменять другие методы.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 2.12.2009, 10:30
Сообщение #16


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Достаточно одного виртуального метода, не обязательно деструктора, даже если этот метод в родительском классе, в производном от него классе, так же создается данная таблица.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
aljeshishe
  опции профиля:
сообщение 2.12.2009, 17:40
Сообщение #17


Студент
*

Группа: Новичок
Сообщений: 12
Регистрация: 1.12.2009
Пользователь №: 1271

Спасибо сказали: 2 раз(а)




Репутация:   0  


Цитата(frg10 @ 1.12.2009, 23:34) *
Цитата(aljeshishe @ 1.12.2009, 19:52) *
void* p = new B;
A* a = (A*)p;

Не делайте так больше никогда. Компилятор не знает ничего о том, что находится по указателю p, поэтому не может корректно привести типы.
Вот так правильно:
    B* p = new B;
    A* a = (A*)p;


Это была выдержка из того что используется в реальном проекте. В различных сторонних библиотеках некоторые методы могут принимать произвольные данные (void*) и эти же данные возвращать. Поскольку менять библиотеку нехорошо приходится приводить свои типы к void*
P.S. Пример был создан в результате безуспешных попыток передать функции QModelIndex QAbstractItemModel::createIndex ( int row, int column, void * ptr = 0 ) свой объект и забрать его обратно через void * QModelIndex::internalPointer () const
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 2.12.2009, 17:49
Сообщение #18


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(aljeshishe @ 2.12.2009, 20:40) *
Пример был создан в результате безуспешных попыток передать функции QModelIndex QAbstractItemModel::createIndex ( int row, int column, void * ptr = 0 ) свой объект и забрать его обратно через void * QModelIndex::internalPointer () const
Хм, вроде тут всё относительно просто:
B *p1, *p2;
p1 = new B;
QAbstractItemModel *model = new QAbstractItemModel(....);
model->createIndex(myRow, myColumn, p1);
...
p2 = model->internalPointer();
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
aljeshishe
  опции профиля:
сообщение 2.12.2009, 18:18
Сообщение #19


Студент
*

Группа: Новичок
Сообщений: 12
Регистрация: 1.12.2009
Пользователь №: 1271

Спасибо сказали: 2 раз(а)




Репутация:   0  


Цитата(Litkevich Yuriy @ 2.12.2009, 17:49) *
Хм, вроде тут всё относительно просто:

Согласен, сложного ничего.
В моем случае в дереве хранятся объекты разных типов: пользователи содержат папки, которые содержат сообщения
Пользователи при этом используют сигналы/слоты.
В функциях index, data, parent модели приходится определять какой тип текущего узла. Для этого есть тип Node:
#include <QObject>
class Node
{
public:
    enum NType
    {
        N_USER,
        N_FOLDER,
        N_MSG
    };
    Node(NType tp_): tp(tp_){};
    NType getType() const{return tp;}
    void setType(NType tp_){tp = tp_;}
private:
    NType tp;

};

class Folder : public Node
{
public:
    Folder() : Node(Node::N_FOLDER), b(2){};
    int b;
};
class User : virtual public QObject,  public Node
{
public:
    User():Node(Node::N_USER), b(2){};
    int b;
};
class Msg : public Node
{
public:
    Msg():Node(Node::N_MSG), b(2){};
    int b;
};
int main(int argc, char* argv[])
{
    void* p = new Folder;
    Node* node = (Node*)p;
    return 0;
}

Решил использовать виртуальное наследование вместо полиморфности Node(все равботает). Правильно ли это?


Хорошая статься в тему
http://www.devdoc.ru/index.php/content/view/virtual_base.htm
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 2.12.2009, 20:54
Сообщение #20


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(aljeshishe @ 2.12.2009, 21:18) *
виртуальное наследование
никогда не слышал про такое
Цитата(aljeshishe @ 2.12.2009, 21:18) *
lass User : virtual public QObject, public Node
За статью спасибо.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

3 страниц V  < 1 2 3 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 28.3.2024, 15:47