AUTOSAR C++14 Rule A10-1-1

Класс не должен быть выведен больше чем из одного базового класса, который не является интерфейсным классом

Описание

Управляйте определением

Класс не должен быть выведен больше чем из одного базового класса, который не является интерфейсным классом.

Объяснение

Если класс наследовался нескольким неинтерфейсным классам, класс по существу имеет доступ к нескольким реализациям. Поддержание кода может затруднить.

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

Предположим, интерфейсный класс Interface имеет две конкретных реализации, Impl1 и Impl2, и класс Final выводит из обеих реализаций. Иерархия классов имеет эту ромбовидную структуру.

Следующие проблемы могут произойти:

  • Переопределения потребовали в итоговом производном классе для разрешения неоднозначности:

    Обе реализации Impl1 и Impl2 имейте копию всех методов класса Interface. Снять неоднозначность, какая копия может быть названа через Final объект, вы обычно создаете еще одно переопределение всех методов в Final класс, где вы вызываете обе копии явным образом с помощью оператора разрешения области видимости :: (или одна копия, если вы выбираете). Смотрите пример ниже.

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

    Если исходный класс Interface не интерфейсный класс, проблема является четной более острая. Если наследования не являются виртуальными, две копии методов Interface неявно сделаны в Impl1 и Impl2 (ромбовидная проблема).

  • Итоговый производный класс, ответственный за инициализацию всех классов в иерархии:

    Чтобы избежать двойных инициализаций во множественном наследовании, стандарт C++ требует, чтобы вы вызвали конструкторов всех предыдущих классов в большей части производного класса.

    В предыдущем примере, Final конструктор класса не только должен вызвать конструкторов Impl1 и Impl2 но также и конструктор их родительского класса Interface. Необходимо проследить вне непосредственных родителей, чтобы определить который конструкторы вызвать в итоговом производном классе.

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

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

Реализация Polyspace

Средство проверки отмечает множественные наследования, где больше чем один базовый класс является неинтерфейсным классом.

Интерфейсный класс является тем, который имеет только чистые виртуальные функции и элементы данных, которые являются константами времени компиляции (статический, contexprS. Любой конструктор или деструктор установлены в =default или =delete.

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

Если вы ожидаете нарушение правила, но не видите его, обратитесь к Кодированию Стандартных Нарушений, Не Отображенных.

Примеры

развернуть все

class Interface {
    public:
    virtual void setVal()=0;
};

class Impl1: public Interface{
    int val1;
public:
    void setVal() {
        val1 = 0;
    }
};

class Impl2: public Interface{
    int val2;
public:
    void setVal() {
        val2 = 0;
    }
};

class Final: public Impl1, public Impl2 { //Noncompliant
public:
    void setVal() {
        Impl1::setVal();
        Impl2::setVal();
    } 
    
};

void main() {
    Final finalObj;
    finalObj.setVal();
}

В этом примере финал класса выводит из классов Impl1 и Impl2. Оба класса Impl1 и Impl2 имейте элементы данных, которые не являются константами времени компиляции и функциями членства, которые не являются чистыми виртуальными функциями. Поэтому классы являются неинтерфейсными классами. Наследование от двух неинтерфейсных классов вызывает нарушение правила кодирования.

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

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