Выбрать главу

Хотя текущее значение _interestRate для всех счетов одинаково, но со временем оно может изменяться. Поэтому мы решили не объявлять этот член как const. Достаточно модифицировать его лишь один раз, и с этого момента все объекты Account будут видеть новое значение. Если бы у каждого объекта была собственная копия, то пришлось бы обновить их все, что неэффективно и является потенциальным источником ошибок.

В общем случае статический член инициализируется вне определения класса. Его имя во внешнем определении должно быть специфицировано именем класса. Вот так можно инициализировать _interestRate:

// явная инициализация статического члена класса

#include "account.h"

double Account::_interestRate = 0.0589;

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

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

#include string

class Account {

// ...

private:

static const string name;

};

const string Account::name( "Savings Account" );

Константный статический член целого типа инициализируется константой внутри тела класса: это особый случай. Если бы для хранения названия счета мы решили использовать массив символов вместо строки, то его размер можно было бы задать с помощью константного члена типа int:

// заголовочный файл

class Account {

//...

private:

static const int nameSize = 16;

static const string name[nameSize];

};

// исходный файл

const string Account::nameSize; // необходимо определение члена

const string Account::name[nameSize] = "Savings Account";

Отметим, что константный статический член целого типа, инициализированный константой, – это константное выражение. Проектировщик может объявить такой статический член, если внутри тела класса возникает необходимость в именованной константе. Например, поскольку константный статический член nameSize является константным выражением, проектировщик использует его для задания размера члена-массива с именем name.

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

Так как name – это массив (и не целого типа), его нельзя инициализировать в теле класса. Попытка поступить таким образом приведет к ошибке компиляции:

class Account {

//...

private:

static const int nameSize = 16; // правильно: целый тип

static const string name[nameSize] = "Savings Account"; // ошибка

};

Член name должен быть инициализирован вне определения класса.

Обратите внимание, что член nameSize задает размер массива name в определении, находящемся вне тела класса:

const string Account::name[nameSize] = "Savings Account";

nameSize не квалифицирован именем класса Account. И хотя это закрытый член, определение name не приводит к ошибке. Как такое может быть? Определение статического члена аналогично определению функции-члена класса, которое может ссылаться на закрытые члены. Определение статического члена name находится в области видимости класса и может ссылаться на закрытые члены, после того как распознано квалифицированное имя Account::name. (Подробнее об области видимости класса мы поговорим в разделе 13.9.)

Статический член класса доступен функции-члену того же класса и без использования соответствующих операторов:

inline double Account::dailyReturn()

{

return( _interestRate / 365 * _amount );

}

Что же касается функций, не являющихся членами класса, то они могут обращаться к статическому члену двумя способами. Во-первых, посредством операторов доступа:

class Account {

// ...

private:

friend int compareRevenue( Account&, Account* );

// остальное без изменения

};

// мы используем ссылочный и указательный параметры,

// чтобы проиллюстрировать оба оператора доступа

int compareRevenue( Account &ac1, Account *ac2 );

{

double ret1, ret2;

ret1 = ac1._interestRate * ac1._amount;

ret2 = ac2-_interestRate * ac2-_amount;

// ...

}

Как ac1._interestRate, так и ac2-_interestRate относятся к статическому члену Account::_interestRate.

Поскольку есть лишь одна копия статического члена класса, до нее необязательно добираться через объект или указатель. Другой способ заключается в том, чтобы обратиться к статическому члену напрямую, квалифицировав его имя именем класса: