- •История
- •Развитие и стандартизация языка
- •Совместимость с языком с
- •Обзор языка
- •Полиморфизм
- •Инкапсуляция
- •Конструкторы и деструкторы
- •Средства c, которых рекомендуется избегать
- •Пример № 5
- •Достоинства
- •Критика
- •Синтаксис
- •Ограниченность возможностей
- •Избыточные и опасные возможности
- •Вычислительная производительность
- •Результативность
- •Влияние и альтернативы
Инкапсуляция
Основным способом организации информации в C++ являются классы. В отличие от структуры (struct) языка C, которая может состоять только из полей и вложенных типов, класс (class) C++ может состоять из полей, вложенных типов и функций-членов (member functions). Инкапсуляция в С++ реализуется через указание уровня доступа к членам класса: они бывают публичными (открытыми, public), защищёнными (protected) и собственными (закрытыми, приватными, private). В C++ структуры формально отличаются от классов лишь тем, что по умолчанию члены и базовые классы у структуры публичные, а у класса — собственные.
Доступ |
private |
protected |
public |
Сам класс |
да |
да |
да |
Друзья |
да |
да |
да |
Наследники |
нет |
да |
да |
Извне |
нет |
нет |
да |
Проверка доступа происходит во время компиляции, попытка обращения к недоступному члену класса вызовет ошибку компиляции.
Пример класса, реализующего одномерный массив (это просто иллюстрация, а не образец дизайна!):
class Array
{
public:
Array() :
len(0),
val(NULL)
{}
Array(int _len) :
len(_len)
{
val = new double[_len];
}
Array(const Array & a);
~Array()
{
Free();
}
inline const double & Elem(int i) const
{
return val[i];
}
inline void ChangeElem(int i, double x)
{
val[i] = x;
}
protected:
void Alloc(int _len)
{
if (len == 0)
Free();
len = _len;
val = new double[len];
}
void Free()
{
delete [] val;
len = 0;
}
int len;
double * val;
};
Здесь класс Array имеет 2 публичных функции-члена, 2 защищённых поля, 3 публичных конструктора и публичный деструктор. Описатель inline означает подсказку компилятору, что вместо вызова функции её код следует встроить в точку вызова, чем часто можно достичь большей эффективности.
Друзья
Функции-друзья — это функции, не являющиеся функциями-членами и тем не менее имеющие доступ к защищённым и закрытым членам класса. Они должны быть объявлены в теле класса как friend. Например:
class Matrix {
...
friend Matrix Multiply(Matrix m1, Matrix m2);
...
};
Matrix Multiply(Matrix m1, Matrix m2) {
...
}
Здесь функция Multiply может обращаться к любым полям и функциям-членам класса Matrix.
Дружественной может быть объявлен как весь класс, так и функция-член класса. Если класс A — объявлен в классе B как друг, то все собственные (не унаследованные) функции-члены класса A могут обращаться к любым членам класса B. Например:
class Matrix {
...
friend class Vector::getNum( Matrix & ) ;
...
private:
int i;
};
...
class Vector
{
int GetNum( Matrix & m ){ return m.i;} //обращение к закрытому члену данных класса Matrix
};
Пример обращения:
void SomeFunction()
{
Matrix m;
Vector v;
int i = Vector::GetNum( m );
}
Четыре важных ограничения, накладываемых на отношения дружественности в C++:
Дружественность не транзитивна. Если A объявляет другом B, а B, в свою очередь, объявляет другом C, то C не становится автоматически другом для A. Для этого A должен явно объявить C своим другом.
Дружественность не взаимна. Если класс A объявляет другом класс B, то он не становится автоматически другом для B. Для этого должно существовать явное объявление дружественности A в классе B.
Дружественность не наследуется. Если A объявляет класс B своим другом, то потомки B не становятся автоматически друзьями A. Для этого каждый из них должен быть объявлен другом A в явной форме.
Дружественность не распространяется на потомков. Если класс A объявляет B другом, то B не становится автоматически другом для классов-потомков A. Каждый потомок, если это нужно, должен объявить B своим другом самостоятельно.
В общем виде это правило можно сформулировать следующим образом: «Отношение дружественности существует только между теми классами (классом и функцией), для которых оно явно объявлено в коде, и действует только в том направлении, в котором оно объявлено».
По действующему стандарту C++ вложенный класс не имеет прав доступа к закрытым членам объемлющего класса и не может быть объявлен его другом (последнее следует из определения термина друг как нечлена класса). В будущем стандарте C++0x эти ограничения будут устранены. В данном отношении современные версии компиляторов VC++, GNU C++ и Comeau C++ даже с отключенными расширениями следуют новым правилам, сформулированным в последних версиях черновика C++0x.
