Everything you do here is fine.
Templates would get you nothing because you still need to store a runtime pointer in the base class for dynamic identification.
Smart pointers would get you nothing because the lifetime of the string is the entire program. If you aren't computing anything, char const *
and initialization from a string literal are ideal. If you are computing the string, then you can use static std::string const
wrapped in a getter function.
class Derived : public Base {
public:
Derived() : Base(get_name()) {}
private:
static std::string const & get_name() {
static std::string const name = "Derived"; // or = compute_name();
return name;
}
};
This avoids the static initialization order fiasco. (The getter function receives an extra multithreading-safe guard from the compiler.) The lifetime of the string
is the lifetime of the program. The Base
may store a string const &
or a char const *
, it doesn't really matter. I would recommend char const *
because the string
reference could potentially be accidentally initialized with a temporary.