May I call a virtual function to initialize a base

2019-01-20 15:02发布

问题:

I know that virtual functions should not be called either directly or indirectly in a constructor, but this code runs fine.
Is what I have here safe?

#include <iostream>
#include <string>

struct A {
    A (const std::string& name) {std::cout << name << std::endl;}
    virtual std::string tag() const = 0;
};

struct B: A {
    B() : A (tag()) {}
    virtual std::string tag() const override {return "B";}
};

int main() {
    B b; // Output gives "B\n"
}

If not, would the following (based on a comment) be a correct workaround?

// Replacement for class B:

struct B: A {
    B() : A (name()) {}
    virtual std::string tag() const override {return name();}
private:
    static std::string name() {return "B";}  // use static function
};

回答1:

Invoking virtual members in the constructor and/or destructor is generally ok.

It's a different game in the ctor initializer though, before all bases are initialized:

12.6.2 Initializing bases and members [class.base.init]

[...]
14 Member functions (including virtual member functions, 10.3) can be called for an object under construction. Similarly, an object under construction can be the operand of the typeid operator (5.2.8) or of a dynamic_cast (5.2.7). However, if these operations are performed in a ctor-initializer (or in a function called directly or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the result of the operation is undefined.