Неправильное объектно-ориентированное программирование

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

Описание

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

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

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

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

  • Вы вызываете функцию членства virtual через неправильный указатель this. Указатель this хранит адрес объекта, используемого, чтобы вызвать функцию. Указатель 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 разыменовывается, проверка 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