Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Gate007 от Июля 12, 2011, 16:32



Название: Помощь в разборе примера, создание класса.
Отправлено: Gate007 от Июля 12, 2011, 16:32
В книге
Макс Шлее - QT Профессиональное программирование на C++
есть следующий пример:
Код
C++ (Qt)
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(bool readonly READ isReadOnly WRITE setReadOnly)
private:
 
bool m_bReadOnly;
public:
MyClass(QObject* pobj = 0) : QObject(pobj)
  , m_bReadOnly(false)
{
}
 
public:
void setReadOnly(bool bReadOnly)
{
m_bReadOnly = bReadOnly;
}
bool isReadOnly() const
{
return m_bReadOnly;
}
}
Вопрос 1:
что делается в строке
Код:
MyClass(QObject* pobj = 0) : QObject(pobj)
   , m_bReadOnly(false)
{
}
Я понимаю что это конструктор, но все явно глубже.
Вопрос 2.
Чуть ниже написано:

Цитировать
Из программы мы можем изменить значение нашего свойства следующим
образом:
pobj->setProperty(„ReadOnly", true);
Или получить текущее значение:
bool bReadOnly = pobj->property("ReadOnly").toBool();

С изменением значения все ясно, а вот с получением... Почему не использована функция isReadOnly()? Я думал что в QT как раз используют методы для получения и изменения полей, а здесь получается что просто обращаются к полю.


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: Пантер от Июля 12, 2011, 16:38
В данном случае можно использовать оба способа. Шлее показывает применение макроса Q_PROPERTY.

П.С. можешь этим не пользоваться. :)


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: kambala от Июля 12, 2011, 17:18
1. это просто конструктор. в нем вызывается конструктор базового класса QObject(pobj) и переменной m_bReadOnly присваивается значение false


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: Igors от Июля 12, 2011, 17:23
Я понимаю что это конструктор, но все явно глубже.
Не надо впадать в крайности (типа "ой как глубоко" или наоборот "та это все фуфло!"). Надо разобраться и иметь свое мнение (это всегда непросто)
С изменением значения все ясно, а вот с получением... Почему не использована функция isReadOnly()? Я думал что в QT как раз используют методы для получения и изменения полей, а здесь получается что просто обращаются к полю.
Ну как это "автор следует собственным рекомендациям"? Они ведь написаны для других :)
П.С. можешь этим не пользоваться. :)
Пока робко но прогресс налицо - рад за Вас  :)


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: lit-uriy от Июля 13, 2011, 08:06
>>Почему не использована функция isReadOnly()?
тут всё просто, Шлее привёл методы чтения и записи свойств (не просто полей класса!!), а именно свойств объектов Qt, которые объявляются при помощи макроса Q_PROPERTY.
С помощью методов setProperty и property можно обращаться к любым свойствам наследников QObject.

Но ещё раз обращаю внимание, не все поля класса являются свойствами, а только те, который объявлены с помощью макроса Q_PROPERTY


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: Gate007 от Июля 13, 2011, 10:58
Если можно, "по слогам", что тут делается?
Код:
MyClass(QObject* pobj = 0) : QObject(pobj)
  , m_bReadOnly(false)
{
}
Это конструктор, понимаю.
Код:
MyClass(QObject* pobj = 0)
Не понимаю
Код:
MyClass(QObject* pobj = 0) : QObject(pobj)
Тоже не понимаю
Код:
 , m_bReadOnly(false) 
Атрибут  m_bReadOnly инициализируется false.
Код:
{
}
Пустое тело конструктора.


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: LisandreL от Июля 13, 2011, 11:05
QObject* pobj = 0 - параметр конструктора (его можно не указывать, тогда он будет равен 0).
: QObject(pobj) - вызываем конструктор родителя.


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: lit-uriy от Июля 13, 2011, 12:11
>>Это конструктор
а конструктор - функция, только не возвращающая ничего (как void), только ради отличия у него нет вообще возвращаемого значения. А раз уж функция, то должны быть скобки, они есть. Но ещё есть и входные аргументы (как указал LisandreL).

>>: QObject(pobj) - вызываем конструктор родителя.
лучше слово родитель заменить на "базовый класс", т.к. в рамках Qt может возникнуть путаница с родственными связями объектов.

конструктор базового класса вызываем, т.к. его тоже надо инициализировать, в нём ведь тоже есть некоторые данные. Если мы явно не вызываем конструктор базового класса, то компилятор это сделает за нас, но он вызовет только конструктор по умолчанию. Нам это не подходит, т.к. мы хотим передать указатель на родительский объект.

>>Атрибут  m_bReadOnly инициализируется false.
только обрати внимание, что выделенное жирным
MyClass(QObject* pobj = 0) : QObject(pobj), m_bReadOnly(false)
называется строка инициализации (если я не путаю) и в ней участвуют только конструкторы.
Т.е.
m_bReadOnly(false) - вызов конструктора объекта m_bReadOnly, с аргументом false.

Для того чтобы переменную инициализировать при объявлении, в Си мы писали так:
bool myvar = true;
В Си++ принято использовать конструктор типа, т.е. так:
bool myvar(true);

А также в Си++ приведение типа принято делать через конструктор:
Си
char mychar = 0x12;
int myint = (int) mychar;

Си++
char mychar(0x12);
int myint = int(mychar); // вызов конструктора типа int c аргументом типа char


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: Пантер от Июля 13, 2011, 12:23
>>Атрибут  m_bReadOnly инициализируется false.
только обрати внимание, что выделенное жирным
MyClass(QObject* pobj = 0) : QObject(pobj), m_bReadOnly(false)
называется строка инициализации (если я не путаю) и в ней участвуют только конструкторы.
Т.е.
m_bReadOnly(false) - вызов конструктора объекта m_bReadOnly, с аргументом false.

Для того чтобы переменную инициализировать при объявлении, в Си мы писали так:
bool myvar = true;
В Си++ принято использовать конструктор типа, т.е. так:
bool myvar(true);
Неверно. Если явно не указать MyClass(QObject* pobj = 0) : QObject(pobj), то QObject инициализируется дефолтом. Пример:
Код
C++ (Qt)
A::A ()
{
 SomeMember = 0;
}
 
Код
C++ (Qt)
A::A ()
: SomeMember (0)
{
 
}
 
Разница в том, что в первом варианте SomeMember сначала проинициализируется каким-то дефолтным значением, а потом ему будет присвоено значение, а во втором варианте все это делается за одно действие.

Цитировать
А также в Си++ приведение типа принято делать через конструктор:
Си
char mychar = 0x12;
int myint = (int) mychar;

Си++
char mychar(0x12);
int myint = int(mychar); // вызов конструктора типа int c аргументом типа char
Ни в коем случае. в С++ принято делать static_cast.


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: Igors от Июля 13, 2011, 12:44
что в первом варианте SomeMember сначала проинициализируется каким-то дефолтным значением, а потом ему будет присвоено значение,
Ничем он не проинициализируется, будет заполнен мусором - ну или как решит malloc или отладчик

Цитировать
int myint = (int) mychar;
...
int myint = int(mychar); // вызов конструктора типа int c аргументом типа char
Ни в коем случае. в С++ принято делать static_cast.
int "старше" (больше по размеру) и тоже знаковый, поэтому простая запись
Код
C++ (Qt)
int myint = mychar;
 
Со всех точек зрения  безопасна, и никакие ухищрения не нужны


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: lit-uriy от Июля 13, 2011, 12:52
>>Неверно. Если явно не указать
в твоей цитате про конструктор QObject речь не шла. Смотри мой пост, абзац выше.

>>Ни в коем случае. в С++ принято делать static_cast.
это уже из более сложной области. Суть моего примера, это уход от того что было принято в Си.


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: LisandreL от Июля 13, 2011, 13:48
что в первом варианте SomeMember сначала проинициализируется каким-то дефолтным значением, а потом ему будет присвоено значение,
Ничем он не проинициализируется, будет заполнен мусором - ну или как решит malloc или отладчик
Для простых типов - будет заполнен мусором, а вот если SomeMember - класс, то будет вызван его конструктор без параметров и выполнится заданная в нём инициализация.


Название: Re: Помощь в разборе примера, создание класса.
Отправлено: Igors от Июля 13, 2011, 13:51
Для простых типов - будет заполнен мусором, а вот если SomeMember - класс, то будет вызван его конструктор без параметров и выполнится заданная в нём инициализация.
Совершенно верно - для POD типов никакой инициализации не выполняется