You'd probably be better off using composition rather than inheritance, but I'll assume you have have a good reason to prefer inheritance here.
The difficulty is that, when a base class constructor is run, the this
pointer is a pointer to an instance of the base class only. The derived instance doesn't even exit yet. (Likewise, on destruction, the derived portion of the object has already been uninitialized). So if you call a virtual method, you'll get the base class implementation rather than the derived class's implementation. In your case, the base class implementation doesn't even exist, so you're stuck.
You can probably get away with casting the base class's this
pointer to a pointer to the derived class, but that's not guaranteed to work and probably involves undefined behavior.
One way to solve this is to store pointers to the base type (InstanceTracker *
) rather the pointers to the derived type. Then your getDerivedPtr
method doesn't need to be virtual, and it can do the cast when it's safe.
template <typename T>
class InstanceTracker {
public:
InstanceTracker() noexcept {
allInstances_.push_back(this);
}
// other constructors elided for space
virtual ~InstanceTracker() noexcept {
std::erase(
std::remove(allInstances_.begin(), allInstances_.end(),
this),
allInstances.end());
}
T* getDerivedPtr() {
return static_cast<T*>(this); // downcast
}
protected:
// allInstances_ stores base class pointers
static std::vector<InstanceTracker*> allInstances_;
};
Notes:
If you use RTTI, run-time type identification, you can use dynamic_cast
instead of static_cast
. You should not use a reinterpret_cast
because the compiler might need to adjust the base pointer as part of the cast.
You're likely to run into problems if you create an instance of a derived type as const
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…