Инкапсуляция основных типов данных в классы - PullRequest
1 голос
/ 13 января 2012

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

Ответы [ 2 ]

5 голосов
/ 13 января 2012

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


Недостатки:

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

Это потенциально полезно, когда вы не хотите перегружать класс 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.

2 голосов
/ 13 января 2012

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

Если у вас есть умный компилятор, класс, который просто оборачивает 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).

В дополнение к этому ваши функции могут обещать очень мало. Какое значение у меня после 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 (в соответствии с общими реализациями). Это означает, что каждому экземпляру вашего класса потребуется немного больше места, чем обычно, и если все ваши числовые значения будут в два раза больше нормального размера, это может сильно снизить производительность в зависимости от того, что вы делаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...