C++. Классы. Использование членов данных класса. Статические члены данных в классе. Статические члены данных для native-классов и managed-классов в среде CLR

C++. Классы. Часть 3. Использование членов данных класса. Статические (static) члены данных в классе. Статические члены данных для native-классов и managed-классов в среде CLR


Содержание


1. Какие виды доступа могут применяться к данным?

Данные и методы класса есть членами класса. Во время объявления данных можно применять все известные способы доступа. Данные могут быть объявлены как: частные (private), защищенные (protected), общедоступные (public).

Более подробно о видах доступа описывается в теме:

2. Можно ли инициализировать данные внутри класса при их объявлении?

Во время объявления данные инициализировать нельзя. Инициализировать данные можно в методах класса, конструкторах класса, внешних методах и т.п. Класс – это не объект, и память под него не выделяется до тех пор, пока не будет создан экземпляр (объект) класса. Данные в классе подобны полям структуры.

3. Как объявить статический член данных в native-классе? Пример объявления и использования

Статический член данных в классе объявляется с помощью ключевого слова static. Поскольку, это есть статический член данных, то нужно его определить (описать переменную) за пределами класса. Доступ к этому статическому члену данных имеют все экземпляры (объекты) класса.

Чтобы использовать статический член данных в классе, нужно:

  • объявить статический член данных в теле класса (в любом разделе класса);
  • определить статический член данных за пределами класса.

Пример. В native-классе (unmanaged-классе) CMyClass объявляется статический член данных с именем d целого типа.

// объявление native-класса
class CMyClass
{
    static int d; // статический член данных - только объявление, память не выделяется

    public:
    CMyClass(void); // конструктор
    ~CMyClass(void); // деструктор

    // методы доступа к статическому члену данных
    int Get(void) { return d; }
    void Set(int nd) { d = nd; }
};

// определение статического члена данных за пределами класса
int CMyClass::d; // выделяется память

// явно заданный конструктор по умолчанию
CMyClass::CMyClass(void)
{
    d = 0;
}

// деструктор
CMyClass::~CMyClass(void)
{
}

Как видно из вышеприведенного кода, с помощью оператора расширения доступа ::’ происходит определение статического члена данных.

Использование статического члена d, объявленного в классе CMyClass из другого метода (программного кода):

// использование статического члена класса
CMyClass MC1; // объект (экземпляр) класса 1
CMyClass MC2; // объект (экземпляр) класса 2

MC2.Set(25);
int t;
t = MC1.Get(); // t = 25 - оба объекта имеют доступ до одному участку памяти

4. Какое правило действует относительно использования статического члена класса экземплярами этого класса?

Если в классе объявлен статический член, то все экземпляры (объекты) класса разделяют между собой этот статический член класса. Точнее говоря, этот статический член класса есть общим для всех объектов этого класса. В отличие от автоматических данных (данных без слова static), не может создаваться нескольких копий статических данных.



5. В какой области памяти распределяется статический член данных?

Статический член данных распределяется в фиксированной области данных. Это происходит на стадии компоновки.

6. Сколько раз выделяется память для статического члена данных?

Память для статического члена данных выделяется на стадии компоновки только один раз в тот момент, когда он определяется. В приведенном выше примере (п. 3) память выделяется в строке

int CMyClass::d;

7. Можно ли инициализировать статический член класса при его объявлении в native-классе?

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

int CMyClass::d = 10; // инициализация статического члена данных

8. Как объявить статический член данных в managed-классе? Пример объявления и использования

В отличие от native-классов, в managed-классах объявление статического члена данных осуществляется как автоматического (без дополнительного определения члена данных). Обязательно нужно задать ключевое слово static.

Так же, как и в native-классах, в managed-классах экземпляры (объекты) класса имеют доступ к одному (только к одному) участку фиксированной памяти.

Пример. Пусть дается класс CMyRefClass, объявленный как managed (управляемый, с ключевым словом ref). Такие классы используются в среде CLR.

// объявление managed-класса
ref class CMyRefClass
{
    private:
    static int rd; // объявление статического члена данных в классе - только один раз

    public:
    CMyRefClass(void); // конструктор по умолчанию

    // методы класса
    int Get(void) { return rd; }
    void Set(int nrd) { rd = nrd; }
};

// определение статического члена - не нужно!
//int CMyRefClass::rd;

// конструктор класса
CMyRefClass::CMyRefClass(void)
{
    rd = 0;
}

Как видно из вышеприведенного кода, для managed-класса не нужно отдельно определять статический член. Использование данного класса из другого метода (программного кода):

// статические члены данных в managed-классах
CMyRefClass RC1;
CMyRefClass RC2;
CMyRefClass ^RC3 = gcnew CMyRefClass(); // managed-указатель на класс

RC2.Set(5);

int t;
t = RC1.Get(); // t = 5

RC3->Set(15);
t = RC2.Get(); // t = 15

RC1.Set(-20);
t = RC3->Get(); // t = -20

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

9. Какие существуют способы доступа к общедоступным (public) статическим членам данных?

Если статический член данных объявлен в разделе public, то доступ к нему можно получить одним из трех способов:

  • с помощью символа ‘ . ‘ (точка), если объявлен объект (экземпляр) класса;
  • с помощью последовательности символов ‘->’, если объявлен указатель на объект класса;
  • с помощью имени класса и символов ‘::’ (расширение области видимости). Этот способ работает также и для статических членов данных, объявленных в разделах private или protected.

10. Пример использования общедоступного статического члена для native-класса

Пусть задан native-класс CMyClass, в котором объявлен общедоступный статический член. В нижеприведенном программном коде продемонстрированы способы доступа к общедоступному статическому члену класса.

// native-класс
class CMyPublicClass
{
    public:
    CMyPublicClass(void);
    ~CMyPublicClass(void);

    static int d; // общедоступный статический член класса

    // методы класса
    int Get() { return d; }
    void Set(int nd) { d = nd; }
};

// определение статического члена класса
int CMyPublicClass::d;

// конструктор
CMyPublicClass::CMyPublicClass(void)
{
    d = 0;
}

// деструктор
CMyPublicClass::~CMyPublicClass(void)
{
}

Демонстрация доступа к статическому члену класса из другого программного кода

// демонстрация доступа к общедоступному статическому члену класса
CMyPublicClass PC1;
CMyPublicClass * PC2 = new CMyPublicClass(); // указатель на класс
int t;

// доступ с помощью символа '.'
PC1.d = 30;
t = PC1.Get(); // t = 30

// доступ с помощью указателя ->
PC2->d = 50;
t = PC2->Get(); // t = 50
t = PC1.Get(); // t = 50

// доступ с помощью оператора расширения области видимости ::
CMyPublicClass::d = -33;
t = PC2->d; // t = -33
t = PC1.d; // t = -33

11. Пример использования общедоступного статического члена для managed-класса

Для managed-класса доступ к статическому члену класса такой же как и для native-класса. Пусть заданы объявления managed-класса CMyPublicClass.

// managed-класс (с идентификатором ref)
ref class CMyPublicClass
{
    public:
    CMyPublicClass(void);
    ~CMyPublicClass(void);

    static int d; // общедоступный статический член класса

    // методы класса
    int Get() { return d; }
    void Set(int nd) { d = nd; }
};

// конструктор
CMyPublicClass::CMyPublicClass(void)
{
    d = 0;
}

// деструктор
CMyPublicClass::~CMyPublicClass(void)
{
}

Демонстрация различных видов доступа

// демонстрация доступа к общедоступному статическому члену класса
CMyPublicClass PC1;
CMyPublicClass ^PC2 = gcnew CMyPublicClass(); // managed-указатель на класс
int t;

// доступ с помощью символа '.'
PC1.d = 30;
t = PC1.Get(); // t = 30

// доступ с помощью указателя ->
PC2->d = 50;
t = PC2->Get(); // t = 50
t = PC1.Get(); // t = 50

// доступ с помощью оператора расширения области видимости ::
CMyPublicClass::d = -33;
t = PC2->d; // t = -33
t = PC1.d; // t = -33

12. Для чего нужны статические члены данных? Преимущества использования статических членов данных

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

Например, можно объявить класс, который содержит статический член данных, который подсчитывает количество активных объектов класса. В этом случае реализуются методы, которые увеличивают (уменьшают) значение этого статического члена. Эти методы могут вызываться из разных частей программного кода (методов других классов и т.п.). Однако, память, которая выделена для этого статического члена данных будет общей для всех этих методов.

13. Какие существуют способы доступа к скрытым статическим членам класса (объявленным в разделе private)?

Если статический член класса объявлен в разделе private, то доступ к нему можно получить одним из трех способов:

  • с помощью оператора расширения области видимости ‘::’;
  • с помощью функции-члена класса (метода класса);
  • с помощью класса, который объявлен дружественным к данному классу.

Если для доступа к скрытому статическому члену данных можно использовать оператор ‘.’ или доступ по указателю ‘->’, то компилятор выдаст ошибку.


Связанные темы