Behaviour of virtual functions in constructors and destructors
suggest changeThe behaviour of virtual functions in constructors and destructors is often confusing when first encountered.
#include <iostream>
using namespace std;
class base {
public:
base() { f("base constructor"); }
~base() { f("base destructor"); }
virtual const char* v() { return "base::v()"; }
void f(const char* caller) {
cout << "When called from " << caller << ", " << v() << " gets called.\n";
}
};
class derived : public base {
public:
derived() { f("derived constructor"); }
~derived() { f("derived destructor"); }
const char* v() override { return "derived::v()"; }
};
int main() {
derived d;
}
Output:
When called from base constructor, base::v() gets called.
When called from derived constructor, derived::v() gets called.
When called from derived destructor, derived::v() gets called.
When called from base destructor, base::v() gets called.
The reasoning behind this is that the derived class may define additional members which are not yet initialized (in the constructor case) or already destroyed (in the destructor case), and calling its member functions would be unsafe. Therefore during construction and destruction of C++ objects, the dynamic type of *this
is considered to be the constructor’s or destructor’s class and not a more-derived class.
Example:
#include <iostream>
#include <memory>
using namespace std;
class base {
public:
base()
{
std::cout << "foo is " << foo() << std::endl;
}
virtual int foo() { return 42; }
};
class derived : public base {
unique_ptr<int> ptr_;
public:
derived(int i) : ptr_(new int(i*i)) { }
// The following cannot be called before derived::derived due to how C++ behaves,
// if it was possible... Kaboom!
int foo() override { return *ptr_; }
};
int main() {
derived d(4);
}
Found a mistake? Have a question or improvement idea?
Let me know.
Behaviour of virtual functions in constructors and destructors
Table Of Contents
2 Literals
9 Arrays
10 Flow control
12 Loops
15 keywords
17 auto keyword
18 Pointers
21 std::string
22 Enumeration
24 std::vector
25 std::array
26 std::pair
27 std::map
30 std::any
31 std::variant
36 std::iomanip
37 Iterators
38 Basic I/O
39 File I/O
40 Streams
44 References
45 Polymorphism
52 Unions
53 Templates
54 Namespaces
57 Lambdas
58 Threading
60 Preprocessor
61 SFINAE
63 RAII
64 Exceptions
68 Sorting
75 Pimpl idiom
76 Copy elision
79 Singleton
82 Type erasure
85 RTTI
88 Scopes
89 Atomic types
91 constexpr
99 Type traits
103 Attributes
105 Profiling
108 Recursion
109 Callable objects
112 Inline functions
114 Header files
117 Parameter packs
118 Iteration
119 type deduction
121 Build systems
123 Type inference
126 Alignment
127 Inline variables
134 Optimization
135 Semaphore
137 Debugging
140 Mutexes
141 Recursive mutex
142 Unit testing
143 decltype
144 Digit separators
145 C++ Containers
147 Contributors