We can static_cast
from Base*
to Derived*
, but in my case the relationship is not visible when the cast is supposed to happen. Is there any trick (besides of reinterpret_cast
of course) to make it work?
struct Derived;
struct Base
{
Base()
{
//Is there a way to make it work?
//Derived* d = static_cast<Derived*>(this);
}
};
struct Derived: public Base
{
};
int main()
{
Base b{};
// Here it works as the compiler is aware of the relationship
Derived* d = static_cast<Derived*>(&b);
}
You can try it here.
Update: Thanks for your comments. Of course, I know that my example code is broken, I just wanted to demonstrate the problem. The real world problem is much more complex.
I have an opaque pointer that points to either Base
or Derived
(compile time switch). And I need that opaque pointer in the constructor of the Base
class. When the opaque pointer is Derived*
then Base
cannot be instantiated just through Derived
, so it is 100% safe. In the other case Base
== Derived
so no cast would happen.
As it is an opaque pointer and we are in Base, we have only a forward declaration of Derived. Like:
#ifdef PLATFORM_A
typedef struct Derived UsedType;
#else
typedef struct Base UsedType;
#endif
So I would need an UsedType*
in the Base constructor, the virtual this is either Base*
or Derived*
. Unfortunately if we are not on PLATFORM_A then Derived is not defined at all, so when the code reaches Base's constructor the compiler cannot know about it's relation with Derived
(as Derived
might not exist at all, and in that case the cast is from Base*
to Base*
).
Update 2: Real world code
Update 3: I updated the code once more. Now there is a member that stores the opaque this pointer. I don't use it in the constructor, I use it only outside. It needs to be initialized in the constructor (as the member is const).
#include <iostream>
#define PLATFORM_A
#ifdef PLATFORM_A
typedef struct Derived UsedType;
#else
typedef struct Base UsedType;
#endif
struct User
{
UsedType* const platform;
void print() const;
};
struct Base
{
const char* const name{"Base"};
User const iNeedThis;
#ifdef PLATFORM_A
protected:
#endif
Base()
: iNeedThis{(UsedType*)this}
//: iNeedThis{static_cast<UsedType*>(this)}
{
}
};
#ifdef PLATFORM_A
struct Derived: public Base
{
const char* const name{"Derived"};
Derived()
: Base()
{
}
};
#endif
void User::print() const
{
std::cout << platform->name << std::endl;
}
int main()
{
UsedType myObj{};
myObj.iNeedThis.print();
}
I mean, it's trivial to do literally what you asked, even without moving the constructor:
struct Base
{
UsedType* self();
#ifdef PLATFORM_A
protected:
#endif
Base()
{
UsedType* iNeedThis = self();
}
};
Later on, in base.cpp or wherever:
#ifndef PLATFORM_A
UsedType* Base::self() { return this; }
#endif
and even later on, in derived.cpp
#ifdef PLATFORM_A
UsedType* Base::self()
{
return static_cast<Derived*>(this);
}
#endif
But it still seems like a bad design.