Самый очевидный вопрос: зачем использовать printf, когда другие инструменты более
адаптироваться? Другой вопрос, который часто забывают, это какой (окончательный) результат
Средняя? Если текст собирается в конечном итоге на принтере или в текстовом поле
оконная система, вы можете вырезать свою работу для вас. Шрифты
На таких системах редко фиксируется ширина, поэтому вам придется принимать во
учитывать ширину отдельных символов. Для вывода на
принтер, я бы предложил вывести LaTeX и затем обработать его.
Для вывода в окно используемая библиотека, вероятно, имеет
компонент таблицы, который сделает форматирование за вас.
Если вы выводите на какое-либо устройство с шрифтом фиксированной ширины & mdash; телетайп, для
Например, вы можете использовать манипуляторы iostream или пользовательские
типы. (Нет способа сделать это чисто с printf
- вам нужно
iostreams.) Абстрактно говоря, определяя такие типы, как Name
, Title
и MonitaryAmount
- самое чистое решение. В этом случае вы просто
определите соответствующий оператор <<
для типа. Использование определенного пользователем
введите имя и заголовок, вместо std::string
, может быть излишним,
однако и подход манипулятора может быть предпочтительным. (В очень большом
приложение, где отдельные типы будут оправданы, вы, скорее всего,
нужен вывод в разных контекстах, и хотите, чтобы манипуляторы указывали
их тоже.)
В простейшем решении вы можете обойтись всего двумя манипуляторами:
TextField
и MoneyField
: каждый манипулятор выходил на поле
ширина в качестве аргумента для конструктора и установить соответствующий формат
поля в своем операторе <<
, например ::
class TextField
{
int myWidth;
public:
TextField( int width ) : myWidth( width ) {}
friend std::ostream&
operator<<( std::ostream& dest, TextField const& manip )
{
dest.setf( std::ios_base::left, std::ios_base::adjustfield );
dest.fill( ' ' );
dest.width( manip.myWidth );
return dest;
}
};
и
class MoneyField
{
int myWidth;
public:
MoneyField( int width ) : myWidth( width ) {}
friend std::ostream&
operator<<( std::ostream& dest, MoneyField const& manip )
{
dest.setf( std::ios_base::right, std::ios_base::adjustfield );
dest.setf( std::ios_base::fixed, std::ios_base::floatfield );
dest.fill( ' ' );
dest.precision( 2 );
dest.width( manip.myWidth );
return dest;
}
};
(С практической точки зрения, вероятно, лучше использовать класс для денег.
Например, вам понадобятся специальные правила округления для умножения; если
Вы рассчитываете налог, на самом деле, вам, вероятно, придется использовать какой-то
десятичного типа, а не double
, для удовлетворения юридических
требования к тому, как он рассчитывается.)
В любом случае, учитывая вышеперечисленные манипуляторы, вы можете написать что-то вроде:
TextField name( 15 );
TextField title( 8 );
MoneyField gross( 8 );
MoneyField tax( 6 );
MoneyField net( 8 );
for ( std::vector< Employee >::const_iterator employee = employees.begin();
employee != employees.end();
++ employee ) {
std::cout << name << employee->name()
<< title << employee->title()
<< gross << employee->salary()
<< tax << calculateTax( employee->salary() )
<< net << calculateNet( employee->salary() )
<< std::endl;
}
(Предполагается, что вы очистили все остальное, чтобы сделать его идиоматическим и
поддерживаемый C ++.)