exponenta event banner

Проверка классов C++

Проверка классов

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

Чтобы сделать ваши классы безопасными для всех возможных контекстов, выполните проверку надежности и удалите как можно больше ошибок во время выполнения.

Программа Polyspace ® Code Prover™ по умолчанию выполняет проверку надежности. Если программное обеспечение предоставляет определение класса вместе с определением методов класса, программное обеспечение моделирует все виды использования класса. Если некоторые определения методов отсутствуют, программа автоматически блокирует их.

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

  2. Программное обеспечение проверяет общедоступные, статические и защищенные методы классов этих объектов при условии, что:

    • Методы могут вызываться в произвольном порядке.

    • Параметры метода могут иметь любое значение в диапазоне, разрешенном их типом данных.

    Для выполнения этой проверки по умолчанию создается main функция, вызывающая методы, которые не вызываются в другом месте кода. Если требуется, чтобы все методы были проверены для всех контекстов, измените это поведение так, чтобы сгенерированные main вызывает все общедоступные и защищенные методы, а не только незакрытые. Дополнительные сведения см. в разделе Functions to call within the specified classes (-class-analyzer-calls).

  3. Программа вызывает деструктор этих объектов (если они существуют) и проверяет их.

При проверке классов Polyspace делает определённые предположения.

Кодовая конструкцияПредположение
Глобальная переменная

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

Например, в следующем коде Polyspace предполагает, что globvar1 может иметь любое значение, разрешенное его типом. Поэтому оранжевое деление на ноль появляется на делении на globvar1. Однако, потому что globvar2 явно инициализирован, деление по нулевой проверке на деление по globvar2 зеленый.

extern int fround(float fx);

// global variables
int globvar1;
int globvar2 = 100;

class Location
{
private:
    int x;

public:
    Location(int intx = 0) {
        x = intx;
    };

    void setx(int intx) {
        x = intx;
    };

    void fsetx(float fx) {
        int tx = fround(fx);
        if (tx / globvar1 != 0)
        {
            tx = tx / globvar2;
            setx(tx);
        }
    };
};

Классы с неопределенными конструкторами

Члены классов могут быть не инициализированы.

В следующем примере Polyspace предполагает, что m_loc.x может не инициализироваться. Поэтому на экране появляется оранжевая неинициализированная ошибка переменной x в getMember способ. После проверки Polyspace предполагает, что переменная может иметь любое значение, разрешенное ее типом. Поэтому оранжевый Overflow появляется в операции добавления в show способ.

class OtherClass
{
protected:
    int x;
public:
    OtherClass (int intx);
    int getMember(void) {
        return x;
    };
};

class MyClass
{
    OtherClass m_loc;
public:
    MyClass(int intx) : m_loc(0) {};
    void show(void) {
        int wx, wl;
        wx = m_loc.getMember();
        wl = wx + 2;
    };
};

Методы и специфика классов

Простой класс

Рассмотрим следующий класс:

Stack.h

#define MAXARRAY 100 

class stack 
{ 
  int array[MAXARRAY]; 
  long toparray; 

public: 
  int top (void); 
  bool isempty (void); 
  bool push (int newval); 
  void pop (void); 
  stack (); 
};

stack.cpp

1 #include "stack.h"
2
3 stack::stack ()
4 {
5     toparray = -1;
6     for (int i = 0 ; i < MAXARRAY; i++)
7     array[i] = 0;
8 }
9
10 int stack::top (void)
11 {
12     int i = toparray;
13     return (array[i]);
14 }
15
16 bool stack::isempty (void)
17 {
18     if (toparray >= 0)
19         return false;
20     else
21         return true;
22 }
23
24 bool stack::push (int newvalue)
25 {
26     if (toparray < MAXARRAY)
27     {
28         array[++toparray] = newvalue;
29         return true;
30     }
31
32     return false;
33 }
34
35 void stack::pop (void)
36 {
37     if (toparray >= 0)
38         toparray--;
39 }

Анализатор классов многократно вызывает конструктор, а затем методы в любом порядке.

Проверка этого класса подчеркивает две проблемы:

  • stack::push способ может записывать после последнего элемента массива, что приводит к проверке оранжевого OBAI в строке 28.

  • Если звонил раньше push, stack::top метод будет обращаться к элементу -1, что приводит к проверкам OBAI и NIV в строке 13.

Устранение этих проблем устранит ошибки во время выполнения в этом классе.

Классы шаблонов

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

  1. Создайте явный экземпляр класса.

  2. Определение typedef экземпляра и предусмотреть, что typedef для проверки.

В следующем примере: calc является классом шаблона, который может обрабатывать любой тип данных через идентификатор myType.

template <class myType> class calc
{
public:
    myType multiply(myType x, myType y);
    myType add(myType x, myType y);
};
template <class myType> myType calc<myType>::multiply(myType x,myType y)
{
    return x*y;
}
template <class myType> myType calc<myType>::add(myType x, myType y)
{
    return x+y;
}

Чтобы проверить этот класс:

  1. Добавьте следующий код в проект Polyspace.

    template class calc<int>;
    typedef calc<int> my_template;

  2. Обеспечить my_template в качестве аргумента параметра Class. См. Class (-class-analyzer).

Абстрактные классы

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

void abstract_func () = 0; by void abstract_func ();

Если для проверки предоставляется абстрактный класс, программное обеспечение выполнит изменение автоматически и виртуальную чистую функцию (abstract_func в приведенном выше примере) будет игнорироваться при проверке абстрактного класса.

Это означает, что ни один вызов не будет сделан из сгенерированного основного, поэтому функция полностью игнорируется. Кроме того, если функция вызывается другой функцией, чистая виртуальная функция будет заблокирована, и на вызов будет помещена оранжевая проверка с сообщением «вызов виртуальной функции [f] может быть чистым».

Рассмотрим следующие классы:

A является абстрактным классом

B является простым классом.

A и B являются базовыми классами C.

C не является абстрактным классом.

Поскольку невозможно создать объект класса A, этот класс нельзя анализировать отдельно от других классов. Поэтому нельзя указывать класс A для анализатора класса Polyspace. Конечно, класс C может быть проанализировано так же, как в предыдущем разделе «Множественное наследование».

Статические классы

Если класс определяет статические методы, он вызывается в сгенерированном главном как классический.

Унаследованные классы

Если функция не определена в производном классе, даже если она видна, поскольку наследуется от класса отца, она не вызывается в сгенерированном главном классе. В приведенном ниже примере класс Point является производным от класса Location:

class Location
{
protected:
    int x;
    int y;
    Location (int intx, int inty);
public:
    int getx(void) {return x;};
    int gety(void) {return y;};
};
class Point : public Location
{
protected:
    bool visible;
public :
    Point(int intx, int inty) : Location (intx, inty)
    {
    visible = false;
    };
    void show(void) { visible = true;};
    void hide(void) { visible = false;};
    bool isvisible(void) {return visible;};
};

Хотя два метода Location::getx и Location::gety являются видимыми для производных классов, сгенерированный основной не включает эти методы при анализе класса Point.

Унаследованные элементы считаются изменчивыми, если они явно не инициализированы в конструкторах отца. В приведенном выше примере два элемента Location::x и Location::y будет считаться изменчивым. Если проанализировать приведенный выше пример в его текущем состоянии, метод Location:: Location(constructor) будут уперты.

Простое наследование

Рассмотрим следующие классы:

A является базовым классом B и D.

B является базовым классом C.

В таком случае программное обеспечение Polyspace позволяет выполнять следующие проверки:

  1. Можно анализировать класс A просто предоставив свой код программному обеспечению. Это соответствует предыдущему разделу «Простой класс» в этой главе.

  2. Можно анализировать класс B путем предоставления своего кода и класса A объявление. В этом случае A код автоматически блокируется программным обеспечением.

  3. Можно анализировать класс B класс путем предоставления B и A коды (объявление и определение). Это проверка «первого уровня интеграции». Анализатор класса не будет вызывать A методы. В этом случае целью является поиск ошибок только в классе B код.

  4. Можно анализировать класс C путем предоставления C код, B объявление класса и A объявление класса. В этом случае A и B коды будут блокироваться автоматически.

  5. Можно анализировать класс C путем предоставления A, B и C код для проверки интеграции. Анализатор класса вызовет все C методы, но не унаследованные методы из B и A. Цель состоит в том, чтобы найти только дефекты в классе C.

В этих случаях нет необходимости предоставлять код класса D для анализа A, B и классы C, если они не используют класс (например, тип элемента) или не нуждаются в нем (например, наследуют).

Множественное наследование

Рассмотрим следующие классы:

A и B являются базовыми классами C.

В этом случае программное обеспечение Polyspace позволяет выполнять следующие проверки:

  1. Можно анализировать классы A и B отдельно, просто предоставляя свои коды программному обеспечению. Это соответствует предыдущему разделу «Простой класс» в этой главе.

  2. Можно анализировать класс C предоставляя свой код с A и B декларации. A и B методы будут блокироваться автоматически.

  3. Можно анализировать класс C путем предоставления A, B и C коды для проверки интеграции. Анализатор класса вызовет все методы C, но не унаследованные методы из A и B. Целью является поиск ошибок только в классе C.

 

Виртуальное наследование

Рассмотрим следующие классы:

B и C классы виртуально наследуют класс A

B и C являются базовыми классами D.

A, B, C и D может быть проанализирован так же, как описано в предыдущем разделе «Абстрактные классы».

Виртуальное наследование не влияет на способ использования анализатора классов.

Интеграция классов

Рассмотрим C класс, наследующий от A и B и имеет элементы объекта AA и BB классы.

Проверка интеграции класса состоит из проверки класса C и предоставление кодов для A, B, AA и BB. Если некоторые определения отсутствуют, программное обеспечение автоматически заглушит их.

См. также