a. Можно, как и обычный локальный (статический или динамический) массив.
б. Только почленно меняя каждый элемент. Однако можно обнулить массив в списке инициализации: array().
Хорошо описано тут
вторник, 29 марта 2011 г.
четверг, 24 марта 2011 г.
51. Влияет ли наличие целочисленных констант-полей на размер класса?
Конечно, ведь каждый объект будет хранить свою константу. Но если константа static, то она будет храниться в одном экземпляре для всех объектов класса, и не повлияет на размер объекта.
среда, 23 марта 2011 г.
50. Для чего служит ключевое слово explicit?
Чтобы запретить неявное преобразование типа, выполняемое конструктором. А вообще такой ворос уже был: 48. Как запретить неявное преобразование типа, выполняемое конструктором инициализации?
вторник, 22 марта 2011 г.
49. Какие проблемы могут возникнуть при определении функций преобразования?
Опять повторюсь, все-таки операции преобразования, а не функции.
Можно столкнуться с неоднозначностью (пример спер):
Компилятор негодует, он не знает то ли преобразовывать первое слагаемое в int (чтобы вызвать обычный operator+(int, int)), то ли второе в Tiny (operator+(Tiny, Tiny)).
Конечно еще существует вероятность случайного неявного преобразования.
Такой оператор следует определить только когда преобразование достаточно очевидно. Но, например, не следует добавлять operator double для вычисления длины вектора, сами же и запутаетесь.
Можно столкнуться с неоднозначностью (пример спер):
struct Tiny{
Tiny(int){}
operator int();
};
int operator+(Tiny, Tiny);
int main() {
Tiny tiny(1);
cout << tiny + 2;
}
Компилятор негодует, он не знает то ли преобразовывать первое слагаемое в int (чтобы вызвать обычный operator+(int, int)), то ли второе в Tiny (operator+(Tiny, Tiny)).
Конечно еще существует вероятность случайного неявного преобразования.
Такой оператор следует определить только когда преобразование достаточно очевидно. Но, например, не следует добавлять operator double для вычисления длины вектора, сами же и запутаетесь.
пятница, 18 марта 2011 г.
48. Как запретить неявное преобразование типа, выполняемое конструктором инициализации?
О конструкторе инициализации я писал в ответе на 46-й вопрос.
Для запрета нужно добавить ключевое слово explicit.
Для запрета нужно добавить ключевое слово explicit.
class A{
public:
explicit A(B);
};
void f(A);
Тогда вызовы, типа f(b)
(b экземпляр B) будут запрещены. Однако всегда можно воспользоваться явным преобразованием f(A(b))
.
47. Для чего нужны функции преобразования? Как объявить такую функцию в классе?
Я уверен, что имеется в виду "оператор преобразования".
Допустим, мы хотим реализовать некоторую цепочку преобразований для объектов классов A, B, C:
A → B → C
Во-первых, можно написать функции преобразования (ну это понятно).
Во-вторых, использовать конструктор (см. вопрос 46). Для этого нужно добавить конструкторы B::B(A) и C::C(B) и преобразовывать на здоровье. Хоть явно, хоть неявно, как в примере:
Я не добавлял никаких операций в класс A, так как B сам преобразовывает A → B. Преобразованием B → C, занимается C. Но часто оказывается так, что нежелательно или невозможно добавить операцию в C, зато B знает как преобразовать себя в C. Тогда нужно использовать оператор преобразования.
Итак, мини-шпаргалка:
Допустим, мы хотим реализовать некоторую цепочку преобразований для объектов классов A, B, C:
A → B → C
Во-первых, можно написать функции преобразования (ну это понятно).
Во-вторых, использовать конструктор (см. вопрос 46). Для этого нужно добавить конструкторы B::B(A) и C::C(B) и преобразовывать на здоровье. Хоть явно, хоть неявно, как в примере:
struct A{
};
struct B{
B(const A&){};
};
struct C{
C(const B&){};
};
int main() {
A a;
B b = a;
C c = b;
}
Я не добавлял никаких операций в класс A, так как B сам преобразовывает A → B. Преобразованием B → C, занимается C. Но часто оказывается так, что нежелательно или невозможно добавить операцию в C, зато B знает как преобразовать себя в C. Тогда нужно использовать оператор преобразования.
struct A{
};
struct C{
};
struct B{
B(const A&){};
operator C(){};
};
int main() {
A a;
B b = a;
C c = b;
}
Итак, мини-шпаргалка:
T → B используем конструктор B::B(T) B → T используем B::operator T()
пятница, 11 марта 2011 г.
46. Какой вид конструктора фактически является конструктором преобразования типов?
Конструктор с одним параметром. Для чего это нужно? Допустим у класса A есть конструктор принимающий единственный параметр - объект класса B. И есть некоторая функция принимающая объект класса A.
Но можно еще проще:
Это приведение бывает полезным. Например (Страуструп 11.3.5), для операций с комплексными числами. Вместо такой стопки функций:
class A{
public:
A(B);
};
void f(A);
Если у нас есть экземпляр класса B, то мы можем воспользоваться конструктором A(B), создать объект A, и передать в функцию:B b;
A a(b);
f(a);
Или, если a не нужен для других целей (будет создан временный объект класса A):B b;
f(A(b));
Но можно еще проще:
B b;
f(b);
Это эквивалентно примеру выше. Компилятор рассуждает так: "Я не могу передать b в f(A), это разные типы, но может быть есть способ преобразовать b к A? Да, можно воспользоваться конструктором A, передав b. Тогда будет создан объект класса A, его и передам в функцию". Это приведение бывает полезным. Например (Страуструп 11.3.5), для операций с комплексными числами. Вместо такой стопки функций:
complex operator+(complex, complex);
complex operator+(complex, double);
complex operator+(double, complex);
можно оставить всего одну (первую), если в Complex создать конструктор Complex(double)
среда, 2 марта 2011 г.
45. Какие конструкции С++ разрешается использовать в списке инициализации качестве инициализирующих выражений?
Что такое список инициализации? Инициализация членов класса путем явного вызова конструктора.
Встретил ответ, что используются lvalue, инициированные rvalue. Его нельзя счесть за правильный, разве что сделать кучу оговорок.
Поэтому, я считаю, правильный ответ: в качестве инициализирующих выражений используются явные вызовы конструкторов.
/* Класс реализующий комплексное число */
class Complex{
...
Complex(float re, float im);
...
};
class Test{
Complex a;
public:
Test():a(3,-2){}
};
Встретил ответ, что используются lvalue, инициированные rvalue. Его нельзя счесть за правильный, разве что сделать кучу оговорок.
int a(1);
++a = 5;
++a это lvalue, так как префиксная операция инкремента возвращает ссылку на объект. Но это не инициализация, и мы не сможем добавить ++a в список инициализации. Но если вы видите, что lvalue инициируется rvalue (int a(1)), то такое можно добавить в список. И можно ли сказать, что a(3,-2) это lvalue инициированное rvalue?Поэтому, я считаю, правильный ответ: в качестве инициализирующих выражений используются явные вызовы конструкторов.
Подписаться на:
Сообщения (Atom)