AUTOSAR C++14 Rule A8-4-14

Интерфейсы должны быть точно и строго типизированы

Описание

Определение правила

Интерфейсы должны быть точно и строго типизированы.

Объяснение

Интерфейсы описывают поведение или возможности объекта. Точно и сильно типизированные интерфейсы определяют назначение и свойства своих параметров с помощью параметров, которые являются пользовательскими объектами и шаблонами вместо фундаментальных типов. Сравните интерфейсы в этом фрагменте кода:

void draw_circle(float R, float x, float y);
void draw_circle(Length R, Position O);
Оба интерфейса представляют функцию, которая рисует круг. Первый интерфейс использует три плавающих числа в качестве входных параметров. Второй интерфейс использует объект класса Length и другой объект класса Position в качестве входных параметров.

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

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

  • Определение классов Length и Position может задать модули этих параметров, такие как см или мм. Определения классов также могут указать, являются ли эти параметры неизменяемыми. Когда вы используете фундаментальные типы в качестве входных параметров, такая спецификация трудна.

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

Когда несколько параметров связаны, объедините их в пользовательский тип. При реализации полиморфных интерфейсов используйте указатели на общий базовый класс вместо указателей на void (void*). Для типовых интерфейсов используйте шаблоны в качестве параметров.

Реализация Polyspace

В Polyspace®, эти типы являются фундаментальными типами:

  • Целые типы, такие как int, short, и long

  • Типы с плавающей точкой, такие как float или double

  • Логический (bool) типы

  • Указатели на пустоту (void*)

  • Указатели или ссылки на предыдущие типы

  • typedef из предыдущих типов

  • Массивы предыдущих типов

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

  • Один или несколько void связанные типы

  • Два или более bool связанные типы

  • Три или более идентичных основных типов

Для уточнения определения интерфейса можно использовать альтернативы, такие как комментарии или имена параметров. В таких случаях можно обосновать результат Polyspace, используя комментарии в своем результате или коде. Смотрите результаты адресации Polyspace посредством исправлений ошибок или обоснований

Поиск и устранение проблем

Если вы ожидаете нарушения правил, но не видите его, обратитесь к разделу «Стандартные нарушения кодирования не отображаются».

Примеры

расширить все

Polyspace флаги интерфейсов, когда их входные параметры включают:

  • Два или более bool связанные типы

  • Три или более идентичных основных типов

Рассмотрим интерфейсы в этом коде:

#include <cstdint>
#include <chrono>

void Sleep(std::uint32_t duration);//Compliant

void SetProperty(bool Status);//Compliant

void SetAlarm(std::uint32_t year, std::uint32_t month, //Noncompliant
              std::uint32_t day, std::uint32_t hour,
              std::uint32_t minute, std::uint32_t second);

//Compliant
void StartClock(std::chrono::system_clock::time_point const& when);
typedef struct {
    int a, b, c, d;
} Point;
void Triangle(float a, float b, float c);//Noncompliant
void Rectangle(Point a, Point b, Point c, Point d); //Compliant

main()
{
    //...
}

  • Polyspace помечает интерфейсы, которые используют три или более переменных фундаментального типа в качестве входных параметров, таких как SetAlarm() и Triangle().

  • Интерфейсы StartClock() и Rectangle() используйте точные и сильно типизированные входные параметры. Polyspace не помечает эти интерфейсы.

  • Polyspace не помечает интерфейс, который имеет менее трех основных входных параметров типа или менее двух bool введите входные параметры.

Polyspace флаги интерфейсы, когда их входные параметры включают один или несколько указателей на void (void*). Рассмотрим интерфейсы в этом коде:

#include <cstdint>

class A{
	//...
};
class B:public A{
	//...
};
class C:public A{
	//...
};

void polymorphic_function(void*);//Noncompliant
void polymorphic_function(A*);//Compliant

void printArray(void* Array);//Noncompliant
template <typename T>
void printArray (T* Array);//Compliant

main(){
	//...
}

Все типы указателей неявно преобразуются в void*, который является слабым и недостаточно квалифицированным типом. Избегайте использования void* указатели.

  • Чтобы реализовать полиморфные интерфейсы, используйте указатели на базовые классы, такие как A* вместо void*.

  • Для реализации типовых интерфейсов используйте такие шаблоны, как T* вместо void*.

Проверяйте информацию

Группа: Деклараторы
Категория: Необходимый, Неавтоматизированный