Делал тестовое задание, что можно было бы сделать лучше или по другому и как вообще делаются подобные приложения с локализациями? Первое что бы сам изменил это использование namespace. И здесь тоже вопрос как лучше организовать его использование?
Задание:
Код | вводим 10-тичное число цифрами, выводим словами на русском языке в 8-ной и 10-ной системах.
Пример. Вводим: 131 Выводим: сто тридцать один в десятичной системе; двести три в восьмеричной системе.
При проектировании подумайте о том, как ваше решение можно было бы локализовать на английский язык (тут обратите внимание, например, на цифру "двести", которая на английском будет состоять из двух слов).
|
Код | //---------------------------------------------------------------------------
#include <iostream> #include <string> #include <vector> #include <cmath> #include <locale>
#include <windows.h> // для CharToOem в to_rus
#define MAX_TEXT_BUF_SIZE 1024
// Переводы, можно вынести в отдельные файлы // Русский перевод #define RUS_RANGE_ERROR "Ошибка диапазона допустимых значений"
#define RUS_0 "ноль" #define RUS_1 "один" #define RUS_2 "два" #define RUS_3 "три" #define RUS_4 "четыри" #define RUS_5 "пять" #define RUS_6 "шесть" #define RUS_7 "семь" #define RUS_8 "восемь" #define RUS_9 "девять"
#define RUS_10 "десять" #define RUS_11 "одинадцать" #define RUS_12 "двенадцать" #define RUS_13 "тринадцать" #define RUS_14 "четырнадцать" #define RUS_15 "пятнадцать" #define RUS_16 "шестнадцать" #define RUS_17 "семнадцать" #define RUS_18 "восемнадцать" #define RUS_19 "девятнадцать"
#define RUS_20 "двадцать" #define RUS_30 "тридцать" #define RUS_40 "сорок" #define RUS_50 "пятьдесят" #define RUS_60 "шестьдесят" #define RUS_70 "семьдесят" #define RUS_80 "восемьдесят" #define RUS_90 "девяносто"
#define RUS_100 "сто" #define RUS_200 "двести" #define RUS_300 "триста" #define RUS_400 "четыриста" #define RUS_500 "пятьсот" #define RUS_600 "шестьсот" #define RUS_700 "семьсот" #define RUS_800 "восемьсот" #define RUS_900 "девятьсот"
//---------------------------------------------------------------------------
// Английский перевод #define ENG_RANGE_ERROR "Out of range"
#define ENG_0 "zero" #define ENG_1 "one" #define ENG_2 "two" #define ENG_3 "three" #define ENG_4 "four" #define ENG_5 "five" #define ENG_6 "six" #define ENG_7 "seven" #define ENG_8 "eight" #define ENG_9 "nine"
#define ENG_10 "ten" #define ENG_11 "eleven" #define ENG_12 "twelve" #define ENG_13 "thirteen" #define ENG_14 "fourteen" #define ENG_15 "fifteen" #define ENG_16 "sixteen" #define ENG_17 "seventeen" #define ENG_18 "eighteen" #define ENG_19 "nineteen"
#define ENG_20 "twenty" #define ENG_30 "thirty" #define ENG_40 "forty" #define ENG_50 "fifty" #define ENG_60 "sixty" #define ENG_70 "seventy" #define ENG_80 "eighty" #define ENG_90 "ninety"
#define ENG_100 "hundred"
//---------------------------------------------------------------------------
using namespace std;
// Проверка на 0 в compile-time // т.к. по условию задачи нельзя использовать BOOST_STATIC_ASSERT // Специализация для false не объявлена template < bool > struct CompileTimeChecker; template <> struct CompileTimeChecker<true> { CompileTimeChecker(...) {}; };
#define STATIC_CHECK( expr ) { sizeof( CompileTimeChecker< (expr) != 0 > ( expr ) ); }
// Базовый класс преобразования числа в строку (Абстрактный) class TNumber_to_string { public: // Конструктор с инициализацией контейнеров TNumber_to_string() :digit_10_19(10), first_digit(10), second_digit(10), third_digit(10) { }
// В 10-ной системе преобразования числа в строку string num_to_str_dec(string const& user_number) { return num_to_str <10> (user_number); }
// В 8-ной системе преобразования числа в строку string num_to_str_oct(string const& user_number) { return num_to_str <8> (user_number); }
// Шаблон функции для 2-10-ной систем преобразования числа в строку // использование шаблона позволит оптимизатору не обращаться // к функции dec_to_other_radix<radix> для преобразования в dec template<unsigned short radix> string num_to_str(string const& user_number) { string output_string; int input_number = atoi(user_number.c_str());
if (input_number < 0 || input_number >= pow(static_cast<double>(radix),3)) output_string = range_error; else if (input_number == 0) output_string = zero_num; else { // Преобразование 10-ной в 10-ную не нужно if (radix != 10) input_number = dec_to_other_radix<radix>(input_number);
// 3-й знак if (input_number > 99) output_string += third_digit[get_dig<10>(input_number, 3)] + " ";
// 2-й знае if (input_number % 100 > 19) output_string += second_digit[get_dig<10>(input_number, 2)] + " ";
// 1-й знак и числа 10-19 if (input_number % 100 > 9 && input_number % 100 < 20) output_string += digit_10_19[get_dig<10>(input_number, 1)] + " "; else output_string += first_digit[get_dig<10>(input_number, 1)]; }
return output_string; }
// Шаблон преобразования из 10-ной в систему с основанием radix template<unsigned short radix> int dec_to_other_radix(int in_num) { int out_num = 0; if (radix == 10) out_num = in_num; else { unsigned int multiplier = 1; while (in_num > 0) { out_num = out_num + (in_num % radix) * multiplier; in_num /= radix; multiplier *= 10; } } return out_num;
}
// Объек класса без языковой локализации создать нельзя virtual string cur_language(void) = 0;
protected: // Контейнеры для хранения строк различных локализаций vector <string> digit_10_19; vector <string> first_digit; vector <string> second_digit; vector <string> third_digit; string zero_num; string range_error;
// Шаблон функции для получения цифры в числе из нужного разряда // radix основание системы исчисления // шаблон позволяет в compile-time проверить деление на 0 template<unsigned short radix> int get_dig(int user_num, unsigned char const& num_dig) { STATIC_CHECK(radix); // Не даст делить на 0 в следующей строке user_num /= pow(static_cast<double>(radix),(num_dig-1)); return user_num % radix; }
};
// Русская локализация class TRus_num_to_str: public TNumber_to_string { public: TRus_num_to_str() { range_error = RUS_RANGE_ERROR; zero_num = RUS_0;
first_digit[0] = ""; first_digit[1] = RUS_1; first_digit[2] = RUS_2; first_digit[3] = RUS_3; first_digit[4] = RUS_4; first_digit[5] = RUS_5; first_digit[6] = RUS_6; first_digit[7] = RUS_7; first_digit[8] = RUS_8; first_digit[9] = RUS_9;
digit_10_19[0] = RUS_10; digit_10_19[1] = RUS_11; digit_10_19[2] = RUS_12; digit_10_19[3] = RUS_13; digit_10_19[4] = RUS_14; digit_10_19[5] = RUS_15; digit_10_19[6] = RUS_16; digit_10_19[7] = RUS_17; digit_10_19[8] = RUS_18; digit_10_19[9] = RUS_19;
second_digit[1] = RUS_10; second_digit[2] = RUS_20; second_digit[3] = RUS_30; second_digit[4] = RUS_40; second_digit[5] = RUS_50; second_digit[6] = RUS_60; second_digit[7] = RUS_70; second_digit[8] = RUS_80; second_digit[9] = RUS_90;
third_digit[1] = RUS_100; third_digit[2] = RUS_200; third_digit[3] = RUS_300; third_digit[4] = RUS_400; third_digit[5] = RUS_500; third_digit[6] = RUS_600; third_digit[7] = RUS_700; third_digit[8] = RUS_800; third_digit[9] = RUS_900; }
string cur_language(void) { return "RUS"; } };
// Английская локализация class TEng_num_to_str: public TNumber_to_string { public: TEng_num_to_str() { range_error = ENG_RANGE_ERROR; zero_num = ENG_0;
first_digit[0] = ""; first_digit[1] = ENG_1; first_digit[2] = ENG_2; first_digit[3] = ENG_3; first_digit[4] = ENG_4; first_digit[5] = ENG_5; first_digit[6] = ENG_6; first_digit[7] = ENG_7; first_digit[8] = ENG_8; first_digit[9] = ENG_9;
digit_10_19[0] = ENG_10; digit_10_19[1] = ENG_11; digit_10_19[2] = ENG_12; digit_10_19[3] = ENG_13; digit_10_19[4] = ENG_14; digit_10_19[5] = ENG_15; digit_10_19[6] = ENG_16; digit_10_19[7] = ENG_17; digit_10_19[8] = ENG_18; digit_10_19[9] = ENG_19;
second_digit[1] = ENG_10; second_digit[2] = ENG_20; second_digit[3] = ENG_30; second_digit[4] = ENG_40; second_digit[5] = ENG_50; second_digit[6] = ENG_60; second_digit[7] = ENG_70; second_digit[8] = ENG_80; second_digit[9] = ENG_90;
third_digit[1] = ENG_100; third_digit[2] = ENG_2; third_digit[3] = ENG_3; third_digit[4] = ENG_4; third_digit[5] = ENG_5; third_digit[6] = ENG_6; third_digit[7] = ENG_7; third_digit[8] = ENG_8; third_digit[9] = ENG_9; for (unsigned char iVec = 2; iVec <= 9; iVec++) { third_digit[iVec] += " "; third_digit[iVec] += ENG_100; }
}
string cur_language(void) { return "ENG"; } };
// Для корректного отображения русских букв string to_rus(string const& text) {
char buf[MAX_TEXT_BUF_SIZE]; CharToOem(text.c_str(), buf); return buf; }
int _tmain(int argc, _TCHAR* argv[]) {
setlocale( LC_ALL, "Russian" ); string user_number, output_string; TRus_num_to_str rus_num2str; // Объект русской локализации TEng_num_to_str eng_num2str; // Объект английской локализации
cin >> user_number;
// Русский { TNumber_to_string &num2str = rus_num2str; cout << to_rus(num2str.num_to_str_dec(user_number)) << endl; cout << to_rus(num2str.num_to_str_oct(user_number)) << endl; cout << num2str.cur_language() << endl; }
// Английский { TNumber_to_string &num2str = eng_num2str; cout << to_rus(num2str.num_to_str_dec(user_number)) << endl; cout << to_rus(num2str.num_to_str_oct(user_number)) << endl; cout << num2str.cur_language() << endl; }
// Класс без локализации - абстрактный - создать не получится // TNumber_to_string num2str;
system ("PAUSE");
return 0; }
|
|