Main Content

Incorrect object oriented programming

Dynamic type of this pointer is incorrect

Description

This check on a class member function call determines if the call is valid.

A member function call can be invalid for the following reasons:

  • You call the member function through a function pointer that points to the function. However, the data types of the arguments or return values of the function and the function pointer do not match.

  • You call a pure virtual member function from the class constructor or destructor.

  • You call a virtual member function through an incorrect this pointer. The this pointer stores the address of the object used to call the function. The this pointer can be incorrect because:

    • You obtain an object through a cast from another object. The objects are instances of two unrelated classes.

    • You perform pointer arithmetic on a pointer pointing to an array of objects. However, the pointer arithmetic causes the pointer to go outside the array bounds. When you dereference the pointer, it is not pointing to a valid object.

Examples

expand all

#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;
}

In this example, the pointer methodPtr has return type int but points to myClass:method that has return type void. Therefore, when methodPtr is dereferenced, the Incorrect object oriented programming check produces a red error.

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

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

In this example, methodPtr has value NULL when it is dereferenced.

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);
}

In this example, the derived class constructor Square::Square calls the base class constructor Shape::Shape() with its this pointer. The base class constructor then calls the pure virtual function Shape::setShapeDimensions through the this pointer. Since the call to a pure virtual function from a constructor is undefined, the Incorrect object oriented programming check produces a red error.

#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();
}

In this example, the classes Foo and Bar are not related. When a Foo* pointer is cast to a Bar* pointer and the Bar* pointer is used to call a virtual member function of class Bar, the Incorrect object oriented programming check produces a red error.

#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;
}

In this example, the pointer FooPtr points outside the allocated bounds when it is used to call the virtual member function func(). It does not point to a valid object. Therefore, the Incorrect object oriented programming check produces a red error.

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) {}
};

In this example, the constructor Bar::Bar() calls the constructor Ref::Ref() with the address of m_Foo before m_Foo is initialized. When the virtual member function func is called through a pointer pointing to &m_Foo, the Incorrect object oriented programming check produces a red error.

To reproduce the results, analyze only the class Bar using the option 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();
}

In this example, you might intend to call the derived class version of funcFoo but depending on your compiler, you call the base class version or encounter a segmentation fault.

The pointer FooPtr points to a Foo object. The cast incorrectly attempts to convert the Foo* pointer FooPtr to a Bar* pointer BarPtr. BarPtr still points to the base Foo object and cannot access Bar::funcFoo.

Correction – Make Base Class Pointer Point Directly to Derived Class Object

C++ polymorphism allows defining a pointer that can traverse the class hierarchy to point to the most derived member function. To implement polymorphism correctly, start from the base class pointer and make it point to a derived class object.

#include <new>

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


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

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

Check Information

Group: C++
Language: C++
Acronym: OOP