A vtable, or virtual function table, is a compiler-generated class table containing addresses for virtual functions. An object uses a pointer to locate the appropriate implementation at runtime. section 8.9
During construction, dispatch follows the part of the object initialized so far. Base-class construction completes first; derived-class table pointers are established only as construction proceeds. This explains why virtual calls from constructors use base-class behavior instead of the final derived override. section 8.9
Mistake: calling a virtual function from a constructor
A Person constructor calls print(), which calls virtual getHonorific(). Constructing a GradStudent prints “Aimee”, then “second year Aimee”, then “candidate Aimee”, because each constructor sees only its initialized class level. Remove virtual calls from constructors and let construction finish before calling print(). section 8.9
Figure 8.1 A three-level hierarchy showing construction order
Trace the A–B–C construction order and see when each class table becomes active. section 8.9
Listing 8.17 Calling virtual functions from a constructor
class Person {
private:
std::string name;
public:
Person(const std::string& name) :
name(name) { print(); } #A
void print() const { std::cout << getHonorific() << name << '\n'; }
const std::string getName() const { return getHonorific() + name; }
virtual std::string getHonorific() const { return ""; }
};
class Student : public Person {
private:
std::string year;
public:
Student(const std::string& name, const std::string& year) : Person(name),
year(year) { print(); }
std::string getHonorific() const { return year + " "; }
};
class GradStudent : public Student {
private:
bool candidate;
public:
GradStudent(const std::string& name, const std::string& year,
bool candidate) : Student(name, year), candidate(candidate)
{ print(); } #1
std::string getHonorific() const {
return candidate ? "candidate " : ""; }
};
int main() {
GradStudent aimee("Aimee", "second year", true);
return 0;
}
Inspect the constructor-based virtual-call example, then compare its output with the safer constructor-free version. section 8.9
