Incorrect object oriented programming

Динамический тип this указатель неправильный

Описание

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

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

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

  • Вы называете чистую virtual Представитель функцию из конструктора классов или деструктора.

  • Вы вызываете virtual Представитель функцию через неправильное this указатель. The this указатель хранит адрес объекта, используемого для вызова функции. The this указатель может быть неправильным, поскольку:

    • Вы получаете объект через приведение от другого объекта. Объекты являются образцами двух несвязанных классов.

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

Примеры

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

#include <iostream>
class myClass {
public: 
  void method() {}
};

void main() {
  myClass Obj;
  int (myClass::*methodPtr) (void) = (int (myClass::*) (void)) &myClass::method;
  int res = (Obj.*methodPtr)();
  std::cout << "Result = " << res;
}

В этом примере указатель methodPtr имеет возвращаемый тип int но указывает на myClass:method который имеет тип возврата void. Поэтому, когда methodPtr dereferenced, проверка Incorrect object oriented programming приводит к красной ошибке.

#include <iostream>
class myClass {
public:
  void method() {}
};

void main() {
  myClass Obj;
  void (myClass::*methodPtr) (void) =  &myClass::method;
  methodPtr = 0;
  (Obj.*methodPtr)();
}

В этом примере methodPtr имеет значение NULL когда это дереферентно.

class Shape {
public:
  Shape(Shape *myShape) {
    myShape->setShapeDimensions(0.0);
  }
  virtual void setShapeDimensions(double) = 0;
};

class Square: public Shape {
  double side;
public:
  Square():Shape(this) {
  }
  void setShapeDimensions(double);
};

void Square::setShapeDimensions(double val) {
  side=val;
}

void main() {
  Square sq;
  sq.setShapeDimensions(1.0);
}

В этом примере конструктор производных классов Square::Square вызывает конструктор базового класса Shape::Shape() с его this указатель. Конструктор базового класса затем вызывает чистую виртуальную функцию Shape::setShapeDimensions через this указатель. Поскольку вызов чистой виртуальной функции от конструктора не определен, проверка Incorrect object oriented programming приводит к красной ошибке.

#include <new>

class Foo {
public:
  void funcFoo() {}
};


class Bar {
public:
  virtual void funcBar() {}
};

void main() {
  Foo *FooPtr = new Foo;
  Bar *BarPtr = (Bar*)(void*)FooPtr;
  BarPtr->funcBar();
}

В этом примере классы Foo и Bar не связаны. Когда Foo* указатель приведен к Bar* указатель и Bar* указатель используется для вызова virtual представитель Bar классовпроверка Incorrect object oriented programming приводит к красной ошибке.

#include <new>
class Foo {
public:
    virtual void func() {}
};

void main() {
    Foo *FooPtr = new Foo[4];
    for(int i=0; i<=4; i++)
        FooPtr++;
    FooPtr->func();
    delete [] FooPtr;
}

В этом примере указатель FooPtr точки за пределами выделенных границ, когда он используется для вызова virtual функции представителя func(). Он не указывает на допустимый объект. Поэтому проверка Incorrect object oriented programming приводит к красной ошибке.

class Foo {
public:
  virtual int func() {
    return 1;
  }
};

class Ref {
public:
  Ref(Foo* foo) {
    foo->func();
  }
};

class Bar {
private:
  Ref m_ref;
  Foo m_Foo;
public:
  Bar() : m_ref(&m_Foo) {}
};

В этом примере конструктор Bar::Bar() вызывает конструктор Ref::Ref() с адресом m_Foo перед m_Foo инициализируется. Когда virtual функции представителя func вызывается через указатель, указывающий на &m_Fooпроверка Incorrect object oriented programming приводит к красной ошибке.

Чтобы воспроизвести результаты, анализируйте только класс Bar использование опции Class (-class-analyzer).

#include <new>

class Foo {
public:
  virtual void funcFoo() {}
};


class Bar: public Foo {
public:
  void funcFoo() {}
};

void main() {
  Foo *FooPtr = new Foo;
  Bar *BarPtr = (Bar*)(void*)FooPtr;
  BarPtr->funcFoo();
}

В этом примере можно намереваться вызвать производную версию класса funcFoo но в зависимости от компилятора, вы вызываете версию базового класса или сталкиваетесь с отказом сегментации.

Указатель FooPtr точки на Foo объект. Приведение неправильно пытается преобразовать Foo* указатель FooPtr в Bar* указатель BarPtr. BarPtr все еще указывает на основу Foo и не может получить доступ к Bar::funcFoo.

Коррекция - Делайте точку указателя базового класса непосредственно к объекту производного класса

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

#include <new>

class Foo {
public:
  virtual void funcFoo() {}
};


class Bar: public Foo {
public:
  void funcFoo() {}
};

void main() {
  Foo *FooPtr = new Bar;
  FooPtr->funcFoo();
}

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

Группа: C++
Язык: C++
Акроним: OOP