вторник, 23 ноября 2010 г.

36. Дайте определение дружественной функции. Как объявляется дружественная функция? А как определяется?

Функция может быть дружественнной не сама по себе, а только по отношению к другим классам. Функция дружественная классу - обычная функция, которой доступны скрытые и защищенные члены этого класса.

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

Пример:
class A{
friend void f(A& a);
int x;
};

void f(A& a){a.x = 1;}

35. Какие операции разрешается перегружать только как методы класса?

= [] () ->

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

34. Какие операции не рекомендуется перегружать как методы класса? Почему?

Даже и не знаю. Страуструп рекомендует перегружать как методы класса только те операторы, которым требуется изменить защищенные члены. Например:
class A{
  int x;
public:
  A& operator+=(int b){x+=b;} //Этому оператор изменяет защищенный член
}

//А этому не нужно менять, и он может воспользоваться оператором +=
A operator+(A& a, int b){A res = a; return res+=b;}

33. Что означает выражение *this? В каких случаях оно используется?

Разыменованный указатель на себя. Часто используется, если функции-члену класса нужно вернуть ссылку на текущий объект:
class A{
  int x;
public:
  A& operator=(const A& a){x = a.x; return *this;} 
}

32. Как различаются перегруженная префиксная и постфиксная операции инкремента и декремента?

Выражение ++a компилятор превращает в вызов operator++(a), а для a++ в вызов operator++(a, int). Параметр int добавлен только для различия сигнатур функций и его значение не используется. Аналогично для декремента.

31. Какой результат должны возвращать операции с присваиванием?

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

class A{
public:
  int x;
  A& operator=(const A& a){x = a.x; return *this;} //переопределили стандартное поведение
  void operator=(int xx){x=xx;} //определили поведение при присваивании целого. Но здесь тоже можно вернуть *this.
};

int main(){
  A a;
  a=1;
  A a2;
  std::cout << (a2=a).x;
}

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

30. Перечислите особенности перегрузки операций как методов класса. Чем отличается перегрузка внешним образом от перегрузки как метода класса?

  • Первый параметр оператора опускается, им становится экземпляр класса (this).
  • Его можно сделать константным методом.
  • У него имеется доступ к не-public членам.
  • Оператор можно сделать виртуальным.
Этим и отличается.

среда, 27 октября 2010 г.

29. Можно ли определить новую операцию?

Нельзя. Технически это было бы несложно, но создало бы больше проблем, чем решило. Допустим, мы решили добавить операцию **, означающую в некоторых языках возведение в степень. Посмотрим, какие возникают трудности.
  • Неоднозначность. Как интерпретировать a**b? (a)**(b) или a*(*b). Заметьте, оба варианта синтаксически корректны, но имеют разный смысл. Придется создавать правила для разрешения этой ситуации.
  • Ассоциативность. Чему эквивалентно a**b**c? (a**b)**c или a**(b**c)?
  • Приоритет. Чему эквивалентно a+b**c? (a+b)**c или a+(b**c)?
Напоминаю, с точки зрения разработчика языка, проблемы не являются неразрешимыми. В некоторых языках есть такая возможность.

вторник, 26 октября 2010 г.

28. Можно ли при перегрузке изменить приоритет операции?

К счастью, нет :) Это создало бы слишком много проблем.

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

27. Можно ли перегружать операции для встроенных типов данных?

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