2012-01-13 5 views
1

Не обсуждая, является ли это хорошей идеей, какие недостатки (производительность или как-то иначе) были бы личными, если бы они инкапсулировали встроенные типы данных C++ в свои собственные классы. Например, подобно Java и C#, тип данных int будет иметь свой собственный класс Int, перегружая его встроенными операторами. То же самое с Single, Double, Long и т. Д.Инкапсулирующие основные типы данных в классы

+6

Могу ли я задать противоположный вопрос? Каковы были бы преимущества? –

+0

Как и во всех таких «прозрачных» оболочках, семантика 'operator &' будет потерянной ситуацией. – Jon

+0

Одно из преимуществ заключается в том, что вы можете наследовать базовый класс. Int32: Integer: Number: Object. Это потенциально полезно, когда вы не хотите перегружать класс Math многими типами, когда достаточно просто Integer или Real. Это также позволяет добавлять новые типы в семейство типов, например, добавление Int128 вниз по строке не повлияет на математический класс. – Dave

ответ

5

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


Недостатками:

  • Производительность никогда не будет быстрее, чем встроенных типов. Лучшее, что вы получите, это класс, в котором все встроено в встроенный код типа, хотя в чем смысл этого?
  • много больше кода не цели
  • Виртуальные вызовы имеют накладные
  • не могут достигнуть идентичное поведение, например, с операторами (Кастинг в первую очередь)
  • нетривиальные конструкторы (не обязательно в C++ 11)
  • Не поддерживается функциями C++, такими как параметры шаблона
  • Confusing. Никто этого не делает.

Это потенциально полезно, если вы не хотите перегружать класс Math со многими типами, когда просто Integer или Real будет достаточно.

У вас есть Java, застрявший в вашей голове.

C++ принимает шаблон подход:

template<typename A_type, typename B_type> 
auto math_operation(A_type a, B_type b) -> decltype(a + b * 2) { 
    return a + b * 2; 
} 

Теперь у вас есть функция, которая работает на любом типе, который поддерживает правильные операторы. Это будет работать для встроенных типов и классов, таких как Int128.

+1

«У вас есть Java, застрявший у вас в голове». - Интересно, есть ли способ вытащить его? :) –

+0

Можете ли вы рассказать о том, какие поведения вы не можете подражать? –

+0

На самом деле его C# застрял у меня в голове, и Java застрял в голове Microsoft: -P – Dave

2

Ясность будет страдать, и это по большей части.

Если у вас есть умный компилятор, класс, который просто обертывает int и не изменяет ни одну из операций, скорее всего, будет полностью вложен. Если вы не определяете конструктор как явный, вы даже сможете написать f(15) за void f(OurVerySpecialInt i). Однако, если есть какие-либо проблемы, у вас будет более сложное время передавать свои специальные сообщения.

Все очень отличается, если вы имеете в виду иерархию классов, а не только класс. Вы хотите, чтобы Numeric был абстрактным базовым классом и Int и Double, чтобы получить от него? В этом случае, пожалуйста, передумайте. Мало того, что вы, скорее всего, получите значительно более медленный код, на самом деле нет способа сделать этот общий и нормальный в то же время.

Рассмотрим класс Numeric, который перегружает operator+. Либо оператор не является членом (как и должно быть), а затем он не может быть виртуальным: поэтому он должен вызывать функцию виртуального члена от Numeric. Но какой?Double() + Double() возвращение Double? Как насчет Double() + Int()? Как насчет Double() + Rational()? В первых двух случаях вы можете сказать «Double, конечно, из-за более возможных значений», но в последнем случае это не работает: если Double является 64-битным, а Rational является частным из двух 32- битных целых чисел, вы будете иметь значения в каждом, которые не могут быть выражены в другом (например, положительная бесконечность и 0,3).

В дополнение к этому, ваши функции могут обещать очень мало. Каково значение i после Int32 i = 250; i += 250;? Я предполагаю, что это 500; а как насчет Int8 = 250; Int8 += 250;? Как насчет Numeric* p = new Int8(250); *p += 250;. Вы не можете волшебным образом сделать *p больше, так что либо вы сделаете ошибку, либо переполняете; в основном, если p - это Numeric*, вы не можете знать, что сделает *p += 50000;: работайте как ожидалось, или переполнения/ошибки, и вы также не можете знать, теряете ли вы точность, когда делаете *p += 5.3.

Если вы исправите эти ошибки, сделав условия более строгими, вы получите какой-то класс Rational или BigInt, который не нуждается в наследовании; все поведение настолько строго указано (как и должно быть с математическими сущностями), что вытекающее из него не позволит вам ничего изменить.

Если этого недостаточно, обратите внимание, что в случае, если вы присвоите классу Numeric любые виртуальные методы, все ваши производные классы будут иметь vtable (под обычными реализациями). Это означает, что для каждого экземпляра вашего класса потребуется немного больше места, чем обычно, и если все ваши числовые значения удваиваются, нормальный размер может сильно повредить производительность в зависимости от того, что вы делаете.

Смежные вопросы