exponenta event banner

MISRA C++: 2008 Правило 10-3-1

На каждом пути в иерархии наследования должно быть не более одного определения каждой виртуальной функции.

Описание

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

На каждом пути в иерархии наследования должно быть не более одного определения каждой виртуальной функции.

Объяснение

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

Внедрение Polyspace

Средство проверки также вызывает нарушение, если функция элемента базового класса переопределена в производном классе без virtual ключевое слово.

Поиск неисправностей

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

Примеры

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

class Base {
    public:
      virtual void foo() {
     }
};

class Intermediate1: public virtual Base {
    public:
      virtual void foo() { //Noncompliant
      }    
};

class Intermediate2: public virtual Base {
    public:
       void bar() {
          foo();  // Calls Base::foo()
      }    
};

class Final: public Intermediate1, public Intermediate2 {
};

void main() {
    Intermediate2 intermediate2Obj;
    intermediate2Obj.bar(); // Calls Base::foo()
    Final finalObj;
    finalObj.bar(); //Calls Intermediate1::foo() 
                    //but you might expect Base::foo()
}

В этом примере virtual функция foo определяется в базовом классе Base а также в производном классе Intermediate1.

Потенциальным источником путаницы может быть следующее. Класс Final извлекает из Intermediate1 а также происходит от Base через другой путь с использованием Intermediate2.

  • Когда Intermediate2 объект вызывает функцию bar который вызывает функцию foo, осуществление foo в Base вызывается. Один Intermediate2 объект не знает о реализации в Intermediate1.

  • Однако, когда Final объект вызывает ту же функцию bar который вызывает функцию foo, осуществление foo в Intermediate1 вызывается из-за доминирования более производного класса.

Если не учитывать это поведение, могут появиться неожиданные результаты.

Чтобы предотвратить эту проблему, объявите функцию чистой виртуальной в базовом классе. Например, можно объявить класс Base следующим образом:

class Base {
    public:
      virtual void foo()=0;
};

void Base::foo() {
      //You can still define Base::foo()
}

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

Группа: Производные классы
Категория: Обязательно
Представлен в R2013b