C++ 2003, Section 5.5 "Pointer-to-member operators", paragraph 4, says:
If the dynamic type of the object does not contain the member to which the pointer refers, the behavior is undefined.
So, trying to use a pointer-to-member operator to access a non-existent member leads to undefined behavior and must be avoided.
Non-Compliant Code Example
In this non-compliant code example there is an abstract base class Shape
and a derived class Circle
that contains a member function area
. The last line of the code following the class definitions results in undefined behavior because there is no member function corresponding to area()
in the class Shape
.
class Shape { // abstract // ... public: virtual void draw() = 0; // ... }; class Circle : public Shape { double radius; public: Circle(double new_radius) : radius(new_radius) {} void draw() { // ... } virtual double area() { return PI*radius*radius; } }; // ... Shape *circ = new Circle(2.0); double(Shape::*circ_area)() = static_cast<double(Shape::*)()>(&Circle::area); cout << "Area: " << (circ->*circ_area)() << endl;
Compliant Solution (Modifiable Base Class)
If the developer is able to change the base class when it is realized that the area()
method is required in the derived class, then a pure virtual area()
method should be added to the class Shape
:
class Shape { // abstract // ... public: virtual void draw() = 0; virtual void area() = 0; // ... }
Compliant Solution (Non-modifiable Base Class)
In many cases, the base class is not modifiable. In this case, one must call the derived method directly.
Circle *circ = new Circle(2.0); cout << "Area: " << (circ->area)() << endl;
Risk Assessment
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
OBJ38-CPP | Medium | Probable | Medium | P8 | L2 |
Bibliography
[ISO/IEC 14882-2003] Section 5.5 "Pointer-to-member operators"
OOP37-CPP. Write constructor member initializers in the canonical order 013. Object Oriented Programming (OOP) 014. Concurrency (CON)