понедельник, 4 октября 2010 г.

6. Является ли структура классом? Чем класс отличается от структуры?

а) Да
б)
класс обявленный как class имеет по умолчанию доступ private,
класс обявленный как struct имеет по умолчанию доступ public.

То есть, такие определения эквиваленты:

class A {
/* */
}

struct A {
private:
/* */
}


Больше отличий нет. На практике обычно структура используется как группировка переменных не требующих задавать поведение для них.

воскресенье, 3 октября 2010 г.

5. Как называется использование объекта одного класса в качестве поля другого класса?

Агрегация. Часто используется ее частный случай - композиция (B - составная часть A, и, в таком случае, А отвечает за создание и уничтожение B)

суббота, 2 октября 2010 г.

4. Допускается ли передавать объекты в качестве параметров, и какими способами? А возвращать как результат?

Так же, как и переменные основных типов - по ссылке(1) и по значению(2).
1. С передачей по ссылке все в принципе ясно: передали ссылку и продолжаем работать с тем же объектом как ни в чем не бывало. Но мне не очень нравится такой способ. Если в коде мы видим:

int x = 1;
f(x);

То мы не можем предугадать, как передан x и может ли измениться его значение в теле функции, так как определение может быть void f(int a) или void f(int &a). Та же неопределенность и при передаче объекта.
Отмечу, что возможности передачи по ссылке не было в C.

2. Если мы не хотим неопределенности, то можно просто передать адрес объекта объекта с помощью указателя (произойдет передача значения указателя). В таком случае код, возможно выглядит не так красиво, но мне нравится больше:

void f(A* a){/* разыменовываем: *a */}

A a;
f(&a);

При передаче объекта по значению будет передано содержимое объекта

void f(A a){/* разыменовываем: *a */}

A a;
f(a);

Будет вызван конструктор копирования.

Возврат результата производится аналогичными способами. Однако важно проследить за временем жизни объекта, иначе можно вернуть ссылку или указатель на уже несуществующий объект. При передаче по значению будет вызван конструктор копирования.

пятница, 1 октября 2010 г.

3. Разрешается ли объявлять указатель на объект? А указатель на класс?

Я много писал об указателях. Ясно, что объявлять указатель на объект конечно же можно.
Вообще говоря, на физическом уровне указатель представляет собой 4 байта, хранящие некоторый адрес. Теоретически можно объявить указатель на все что угодно, что занимает место в оперативной памяти. Но класс не хранится в явном виде в памяти.

Но ради интереса можно подумать что представляет собой класс на низком уровне.

class A{
int x;
int f(){return 1};
}

Если класс не используется в программе, то компилятор, скорее всего пропустит это объявление. Но допустим мы создали объект: A a; но где лежит информация, что член x имеет тип int, и занимает 4 (на других платформах может и не 4) байта? В исходном коде. Именно оттуда компилятор берет эту информацию и генерирует соответствующий код.
А вот код функции f() действительно загружается в память. Она скорее всего будет иметь свой адрес. А может и не будет, например, если компилятор или автор решит сделать ее встроенной (inline).
Как видим, в явном виде класс не хранится.

четверг, 30 сентября 2010 г.

2. Можно ли объявлять массив объектов? А массив классов?

С массивом объектов все ясно:

class A {
public:
int x;
};

A a[3];
//либо динамически:
//A* a = new A[3];
//(важно не забыть delete[] a;)
a[0].x = 1;
a[1].x = 2;
a[2].x = 3;

std::cout << a[0].x << a[1].x << a[2].x;


Переходим к следующему подвопросу. В Delphi можно было провернуть такую штуку:

type

A = class
end;

A1 = class(A)
end;

A2 = class(A)
end;

classA = class of A;

var
classArray : array[1..2] of classA;
objArray : array[1..2] of A;
i : Integer;

begin
classArray[1] := A1;
classArray[2] := A2;
for i := 1 to 2 do
begin
objArray[i] := classArray[i].Create();
ShowMessage(objArray[i].ClassName);
end;
end;

То есть действительно реализовать некий массив классов (можно ли его так назвать?). В C++ я был не очень уверен и погуглил "массив классов". Можно сделать похожий механизм через порождающие фабрики. Но так как это не массив, в обычном понимании, и это только 2-й вопрос, то ответ - "нельзя".
А еще поиск ответа показал, что очень многие спрашивают про "массив классов" имея в виду "массив объектов". Значит первый вопрос (чем обличается класс от объекта?) вполне актуален :)

среда, 29 сентября 2010 г.

1. Что определяет класс? Чем отличается класс от объекта?

Класс определяет структуру и поведение. Объект определяет состояние (наполнение структуры) и меняет его в зависимости от поведения, заданным классом.
Вопрос "Чем отличается класс от объекта?" задает экзаменатор студенту, когда пытается вытащить его на троечку. А студент даже не открывал первую страницу отксеренных лекций. Это примерно то же самое, что спрашивать: "А чем вот этот Тузик(см. рис.) отличается от биологического подвида "собака домашняя"?".

пятница, 24 сентября 2010 г.

Большой список вопросов на знание C++

http://www.rsdn.ru/forum/cpp/1870577.1.aspx
Целых 385 вопросов. От простых до очень сложных.
Буду отвечать понемногу, и помечать топики с ответами меткой "385"

воскресенье, 8 августа 2010 г.

QT интернационализация.

Хорошие статьи о создании поддержки нескольких языков в приложении.
1. Qt — трудности перевода
2. Локализация и числительные

суббота, 7 августа 2010 г.

QT. Цвета виджета.

QPalette p = MyLabel->palette();
p.setColor(QPalette::Window, Qt::black); //фон
p.setColor(QPalette::WindowText, Qt::red); //шрифт
MyLabel->setWidget(p);


все.

пятница, 6 августа 2010 г.

QT. QObject. Первые ошибки. Collect2: ld returned 1 exit status.

В связи со срочностью написания приложения на QT, была бегло пролистана соответствующая книжка. За эту спешку поплатился кучей глупых ошибок. Решил собрать коллекцию таких, на которые MinGW невразумительно ругается :)

При работе с QObject, очень просто получить такое:
1. no matching function for call to 'QObject::connect(...)'
2. undefined reference to 'vtable for MyClass'
3. collect2: ld returned 1 exit status

Последняя ошибка на первом месте моего хит-парада неприятных ошибок :)

Итак, если мы хотим использовать объект QObject, нужно не забывать:

  • Определять классы, использующие макрос Q_OBJECT в заголовочном файле (а не cpp). Иначе схлопочем ошибки 1 и 3.
  • Вставлять макроса Q_OBJECT (Ошибка 1). Примечание: если собрать проект без этого макроса, потом вставить его и опять попробовать собрать, то можно получить ошибки 2 и 3. Нужно произвести чистку проекта (или тупо грохнуть папку с билдом. В QT Creator она по умолчанию-MyProject-build-desktop)
  • Наследоваться от QObject, или его производного класса (Ошибка 1).
  • Вставлять #include . Ошибки можно и не получить, но сигналы и слоты работать не будут.
  • Определять объявленные слоты, если не хотим получить ошибку 3. С этим я конкретно намучался. "collect2: ld returned 1 exit status" и все! Ну как тут понять, что я просто забыл написать тело для слота MyClass::mySlot(){/* */}


UPD (7.08.10 18:25):
Блин, мне было нужно смотреть консоль сборки (QT Creator). Я бы сразу увидел дополнительную информацию о причинах ошибки.