• Новости
  • Темы
    • Экономика
    • Здоровье
    • Авто
    • Наука и техника
    • Недвижимость
    • Туризм
    • Спорт
    • Кино
    • Музыка
    • Стиль
  • Спецпроекты
  • Телевидение
  • Знания
    • Энциклопедия
    • Библия
    • Коран
    • История
    • Книги
    • Наука
    • Детям
    • КМ школа
    • Школьный клуб
    • Рефераты
    • Праздники
    • Гороскопы
    • Рецепты
  • Сервисы
    • Погода
    • Курсы валют
    • ТВ-программа
    • Перевод единиц
    • Таблица Менделеева
    • Разница во времени
Ограничение по возрасту 12
KM.RU
Рефераты
Главная → Рефераты → Информатика, программирование
  • Новости
  • В России
  • В мире
  • Экономика
  • Наука и техника
  • Недвижимость
  • Авто
  • Туризм
  • Здоровье
  • Спорт
  • Музыка
  • Кино
  • Стиль
  • Телевидение
  • Спецпроекты
  • Книги
  • Telegram-канал

Поиск по рефератам и авторским статьям

Определяемое Преобразование Типа

Приведенная во введении реализация комплексных чисел слишком ограничена, чтобы она могла устроить кого-либо, поэтому ее нужно расширить. Это будет в основном повторением описанных выше методов.

Например:

class complex {

  double re, im;

public:

  complex(double r, double i) { re=r; im=i; }

  friend complex operator+(complex, complex);

  friend complex operator+(complex, double);

  friend complex operator+(double, complex);

  friend complex operator-(complex, complex);

  friend complex operator-(complex, double);

  friend complex operator-(double, complex);

  complex operator-()     // унарный -

  friend complex operator*(complex, complex);

  friend complex operator*(complex, double);

  friend complex operator*(double, complex);

  // ...

};

Теперь, имея описание complex, мы можем написать:

void f()

{

  complex a(1,1), b(2,2), c(3,3), d(4,4), e(5,5);

  a = -b-c;

  b = c*2.0*c;

  c = (d+e)*a;

}

Но писать функцию для каждого сочетания complex и double, как это делалось выше для operator+(), невыносимо нудно. Кроме того, близкие к реальности средства комплексной арифметики должны предоставлять по меньшей мере дюжину таких функций; посмотрите, например, на тип complex.

Конструкторы

Альтернативу использованию нескольких функций (перегруженных) составляет описание конструктора, который по заданному double создает complex.

Например:

class complex {

  // ...

  complex(double r) { re=r; im=0; }

};

Конструктор, требующий только один параметр, необязательно вызывать явно:

complex z1 = complex(23);

complex z2 = 23;

И z1, и z2 будут инициализированы вызовом complex(23).

Конструктор - это предписание, как создавать значение данного типа. Когда требуется значение типа, и когда такое значение может быть создано конструктором, тогда, если такое значение дается для присваивания, вызывается конструктор.

Например, класс complex можно было бы описать так:

class complex {

  double re, im;

public:

  complex(double r, double i = 0) { re=r; im=i; }

  friend complex operator+(complex, complex);

  friend complex operator*(complex, complex);

};

и действия, в которые будут входить переменные complex и целые константы, стали бы допустимы. Целая константа будет интерпретироваться как complex с нулевой мнимой частью. Например, a=b*2 означает:

a=operator*( b, complex( double(2), double(0) ) )

Определенное пользователем преобразование типа применяется неявно только тогда, когда оно является единственным.

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

Операции Преобразования

Использование конструктора для задания преобразования типа является удобным, но имеет следствия, которые могут оказаться нежелательными:

Не может быть неявного преобразования из определенного пользователем типа в основной тип (поскольку основные типы не являются классами);

Невозможно задать преобразование из нового типа в старый, не изменяя описание старого; и

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

Последнее не является серьезной проблемой, а с первыми двумя можно справиться, определив для исходного типа операцию преобразования. Функция член X::operator T(), где T - имя типа, определяет преобразование из X в T. Например, можно определить тип tiny (крошечный), который может иметь значение только в диапазоне 0...63, но все равно может свободно сочетаться в целыми в арифметических операциях:

class tiny {

char v;

int assign(int i)

{ return v = (i&~63) ? (error("ошибка диапазона"),0) : i; }

public:

tiny(int i) { assign(i); }

tiny(tiny& i) { v = t.v; }

int operator=(tiny& i) { return v = t.v; }

int operator=(int i) { return assign(i); }

operator int() { return v; }

}

Диапазон значения проверяется всегда, когда tiny инициализируется int, и всегда, когда ему присваивается int. Одно tiny может присваиваться другому без проверки диапазона. Чтобы разрешить выполнять над переменными tiny обычные целые операции, определяется tiny::operator int(), неявное преобразование из int в tiny. Всегда, когда в том месте, где требуется int, появляется tiny, используется соответствующее ему int.

Например:

void main()

{

tiny c1 = 2;

tiny c2 = 62;

tiny c3 = c2 - c1; // c3 = 60

tiny c4 = c3; // нет проверки диапазона (необязательна)

int i = c1 + c2; // i = 64

c1 = c2 + 2 * c1; // ошибка диапазона: c1 = 0 (а не 66)

c2 = c1 -i; // ошибка диапазона: c2 = 0

c3 = c2; // нет проверки диапазона (необязательна)

}

Тип вектор из tiny может оказаться более полезным, поскольку он экономит пространство. Чтобы сделать этот тип более удобным в обращении, можно использовать операцию индексирования.

Другое применение определяемых операций преобразования - это типы, которые предоставляют нестандартные представления чисел (арифметика по основанию 100, арифметика с фиксированной точкой, двоично-десятичное представление и т.п.). При этом обычно переопределяются такие операции, как + и *.

Функции преобразования оказываются особенно полезными для работы со структурами данных, когда чтение (реализованное посредством операции преобразования) тривиально, в то время как присваивание и инициализация заметно более сложны.

Типы istream и ostream опираются на функцию преобразования, чтобы сделать возможными такие операторы, как while (cin>>x) cout<>x выше возвращает istream&. Это значение неявно преобразуется к значению, которое указывает состояние cin, а уже это значение может проверяться оператором while . Однако определять преобразование из оного типа в другой так, что при этом теряется информация, обычно не стоит.

Неоднозначности

Присваивание объекту (или инициализация объекта) класса X является допустимым, если или присваиваемое значение является X, или существует единственное преобразование присваиваемого значения в тип X.

В некоторых случаях значение нужного типа может сконструироваться с помощью нескольких применений конструкторов или операций преобразования. Это должно делаться явно; допустим только один уровень неявных преобразований, определенных пользователем. Иногда значение нужного типа может быть сконструировано более чем одним способом. Такие случаи являются недопустимыми.

Например:

class x { /* ... */ x(int); x(char*); };

class y { /* ... */ y(int); };

class z { /* ... */ z(x); };

overload f;

x f(x);

y f(y);

z g(z);

f(1); // недопустимо: неоднозначность f(x(1)) или f(y(1))

f(x(1));

f(y(1));

g("asdf"); // недопустимо: g(z(x("asdf"))) не пробуется

g(z("asdf"));

Определенные пользователем преобразования рассматриваются только в том случае, если без них вызов разрешить нельзя.

Например:

class x { /* ... */ x(int); }

overload h(double), h(x);

h(1);

Вызов мог бы быть проинтерпретирован или как h(double(1)), или как h(x(1)), и был бы недопустим по правилу единственности. Но первая интерпретация использует только стандартное преобразование и она будет выбрана по правилам. Правила преобразования не являются ни самыми простыми для реализации и документации, ни наиболее общими из тех, которые можно было бы разработать. Возьмем требование единственности преобразования. Более общий подход разрешил бы компилятору применять любое преобразование, которое он сможет найти; таким образом, не нужно было бы рассматривать все возможные преобразования перед тем, как объявить выражение допустимым. К сожалению, это означало бы, что смысл программы зависит от того, какое преобразование было найдено. В результате смысл программы неким образом зависел бы от порядка описания преобразования. Поскольку они часто находятся в разных исходных файлах (написанных разными людьми), смысл программы будет зависеть от порядка компоновки этих частей вместе. Есть другой вариант - запретить все неявные преобразования. Нет ничего проще, но такое правило приведет либо к неэлегантным пользовательским интерфейсам, либо к бурному росту перегруженных функций, как это было в предыдущем разделе с complex.

Самый общий подход учитывал бы всю имеющуюся информацию о типах и рассматривал бы все возможные преобразования. Например, если использовать предыдущее описание, то можно было бы обработать aa=f(1), так как тип aa определяет единственность толкования. Если aa является x, то единственное, дающее в результате x, который требуется присваиванием, - это f(x(1)), а если aa - это y, то вместо этого будет использоваться f(y(1)). Самый общий подход справился бы и с g("asdf"), поскольку единственной интерпретацией этого может быть g(z(x("asdf"))). Сложность этого подхода в том, что он требует расширенного анализа всего выражения для того, чтобы определить интерпретацию каждой операции и вызова функции. Это приведет к замедлению компиляции, а также к вызывающим удивление интерпретациям и сообщениям об ошибках, если компилятор рассмотрит преобразования, определенные в библиотеках и т.п. При таком подходе компилятор будет принимать во внимание больше, чем, как можно ожидать, знает пишущий программу программист!

Список литературы

Для подготовки данной работы были использованы материалы с сайта http://www.realcoding.net

Дата добавления: 03.10.2006

База рефератов на портале KM.RU существует с 1999 года. Она пополнялась не только готовыми рефератами, докладами, курсовыми, но и авторскими публикациями, чтобы учащиеся могли использовать их и цитировать при самостоятельном написании работ.


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


Уважаемые авторы! Если Вы все же возражаете против размещения Вашей публикации или хотите внести коррективы, напишите нам на почту info@corp.km.ru, мы незамедлительно выполним Вашу просьбу или требование.


официальный сайт © ООО «КМ онлайн», 1999-2025 О проекте ·Все проекты ·Выходные данные ·Контакты ·Реклама
]]>
]]>
Сетевое издание KM.RU. Свидетельство о регистрации Эл № ФС 77 – 41842.
Мнения авторов опубликованных материалов могут не совпадать с позицией редакции.

Мультипортал KM.RU: актуальные новости, авторские материалы, блоги и комментарии, фото- и видеорепортажи, почта, энциклопедии, погода, доллар, евро, рефераты, телепрограмма, развлечения.

Карта сайта


Подписывайтесь на наш Telegram-канал и будьте в курсе последних событий.


Организации, запрещенные на территории Российской Федерации
Telegram Logo

Используя наш cайт, Вы даете согласие на обработку файлов cookie. Если Вы не хотите, чтобы Ваши данные обрабатывались, необходимо установить специальные настройки в браузере или покинуть сайт.