Virtual functions allow for the choice of member function calls to be determined at run time based on the dynamic type of the object that the member function is being called on. This convention supports object-oriented programming practices commonly associated with object inheritance and function overriding. When calling a nonvirtual member function or when using a class member access expression to denote a call, the specified function is called. Otherwise, a virtual function call is made to the final overrider in the dynamic type of the object expression. Show
However, during the construction and destruction of an object, the rules for virtual method dispatch on that object are restricted. The C++ Standard, [class.cdtor], paragraph 4 [ISO/IEC 14882-2014], states the following:
Do not directly or indirectly invoke a virtual function from a constructor or destructor that attempts to call into the object under construction or destruction. Because the order of construction starts with base classes and moves to more derived classes, attempting to call a derived class function from a base class under construction is dangerous. The derived class has not had the opportunity to initialize its resources, which is why calling a virtual function from a constructor does not result in a call to a function in a more derived class. Similarly, an object is destroyed in reverse order from construction, so attempting to call a function in a more derived class from a destructor may access resources that have already been released. Noncompliant Code ExampleIn this noncompliant code example, the base class attempts to seize and release an object's resources through calls to virtual
functions from the constructor and destructor. However, the struct B { B() { seize(); } virtual ~B() { release(); } protected: virtual void seize(); virtual void release(); }; struct D : B { virtual ~D() = default; protected: void seize() override { B::seize(); // Get derived resources... } void release() override { // Release derived resources... B::release(); } }; The result of running this code is that no derived class resources will be seized or released during the initialization and destruction of object of type Compliant SolutionIn this compliant solution, the constructors and destructors call a nonvirtual, private member function (suffixed with class B { void seize_mine(); void release_mine(); public: B() { seize_mine(); } virtual ~B() { release_mine(); } protected: virtual void seize() { seize_mine(); } virtual void release() { release_mine(); } }; class D : public B { void seize_mine(); void release_mine(); public: D() { seize_mine(); } virtual ~D() { release_mine(); } protected: void seize() override { B::seize(); seize_mine(); } void release() override { release_mine(); B::release(); } }; ExceptionsOOP50-CPP-EX1: Because valid use cases exist that involve calling (non-pure) virtual functions from the constructor of a class, it is permissible to call the virtual function with an explicitly qualified ID. The qualified ID signifies to code maintainers that the expected behavior is for the class under construction or destruction to be the final overrider for the function call. struct A { A() { // f(); // WRONG! A::f(); // Okay } virtual void f(); }; OOP50-CPP-EX2: It is permissible to call a virtual function that has the struct A { A(); virtual void f(); }; struct B : A { B() : A() { f(); // Okay } void f() override final; }; Similarly, it is permissible to call a virtual function from a constructor or destructor of a class that has the struct A { A(); virtual void f(); }; struct B final : A { B() : A() { f(); // Okay } void f() override; }; In either case, Risk Assessment
Automated Detection
Search for other vulnerabilities resulting from the violation of this rule on the CERT website. Bibliography
Which type of member function may only be called from a function that is a member of the same class?A private member function may only be called from a function that is a member of the same class.
When a member function is defined outside of the class declaration the function name must be?If you define a member function outside of its class definition, it must appear in a namespace scope enclosing the class definition. You must also qualify the member function name using the scope resolution ( :: ) operator.
When a class object is created this member function is automatically called?10. What is a constructor? A constructor is a member function that has the same name as the class. It is automatically called when the object is created in memory, or instantiated.
Which of the following is a directive used to prevent a header file from accidentally being included more than once?Another way to prevent a header file from being included more than once is with the ` #pragma once ' directive.
|