I would like to cast a pointer to a member of a derived class to void*
and from there to a pointer of the base class, like in the example below:
我想将指向派生类的成员的指针转换为void *并从那里转换为基类的指针,如下例所示:
#include <iostream>
class Base
{
public:
void function1(){std::cout<<"1"<<std::endl;}
virtual void function2()=0;
};
class Derived : public Base
{
public:
virtual void function2(){std::cout<<"2"<<std::endl;}
};
int main()
{
Derived d;
void ptr* = static_cast<void*>(&d);
Base* baseptr=static_cast<Base*>(ptr);
baseptr->function1();
baseptr->function2();
}
This compiles and gives the desired result (prints 1
and 2
respectively), but is it guaranteed to work? The description of static_cast
I found here: http://en.cppreference.com/w/cpp/language/static_cast only mentions conversion to void*
and back to a pointer to the same class (point 10).
这会编译并给出所需的结果(分别打印1和2),但它是否可以保证有效?我在这里找到的static_cast描述:http://en.cppreference.com/w/cpp/language/static_cast只提到转换为void *并返回指向同一个类的指针(第10点)。
3 个解决方案
#1
8
In the general case, converting a base to void to derived (or vice versa) via static casting is not safe.
在一般情况下,通过静态铸造将基础转换为空白到导出(反之亦然)是不安全的。
There will be cases where it will almost certainly work: if everything involved is a pod, or standard layout, and only single inheritance is involved, then things should be fine, at least in practice: I do not have chapter and verse from the standard, but the general idea is that the base in that case is guaranteed to be the prefix of the derived, and they will share addresses.
有些情况下它几乎肯定会起作用:如果涉及的所有内容都是一个pod或标准布局,并且只涉及单一继承,那么事情应该没问题,至少在实践中是这样的:我没有标准的章节和经文,但一般的想法是,在这种情况下,基数保证是派生的前缀,并且它们将共享地址。
If you want to start seeing this fail, mix in virtual
inheritance, multiple inheritance (both virtual
and not), and multiple implementation inheritance that are non trivial. Basically when the address of the different type views of this
differ, the void
cast from and back to a different type is doomed. I have seen this fail in practice, and the fact it can fail (due to changes in your code base far away from the point of casting) is why you want to be careful about always casting to and from void pointer with the exact same type.
如果你想开始看到这个失败,混合虚拟继承,多重继承(虚拟和非虚拟),以及多个非常重要的实现继承。基本上当不同类型视图的地址不同时,从不同类型转换回来的空隙注定要失败。我已经看到这在实践中失败,并且它可能失败的事实(由于代码库的变化远离投射点)是你为什么要小心总是使用完全相同类型的void指针进行强制转换。
#2
3
In general, no, it is not safe.
一般来说,不,它不安全。
Suppose that casting Derived*
directly to Base*
results in a different address (for example, if multiple inheritance or virtual inheritance is involved).
假设将Derived *直接转换为Base *会导致不同的地址(例如,如果涉及多个继承或虚拟继承)。
Now if you inserted a cast to void*
in between, how would the compiler know how to convert that void*
to an appropriate Base*
address?
现在,如果你在中间插入一个转换为void *,编译器将如何知道如何将该void *转换为适当的Base *地址?
If you need to cast a Derived*
to a void*
, you should explicitly cast the void*
back to the original Derived*
type first. (And from there, the cast from Derived*
to Base*
is implicit anyway, so you end up with the same number of casts, and thus it's not actually less any convenient.)
如果需要将Derived *强制转换为void *,则应首先将void *显式地转换回原始的Derived *类型。 (从那里,从Derived *到Base *的演员阵容无论如何都是隐含的,所以你最终会得到相同数量的演员阵容,因此它实际上并没有那么方便。)
#3
0
From the link you supplied yourself
从您自己提供的链接
9) A pointer to member of some class D can be upcast to a pointer to member of its base class B. This static_cast makes no checks to ensure the member actually exists in the runtime type of the pointed-to object.
9)指向某个类D成员的指针可以向上转换为指向其基类B成员的指针。此static_cast不进行检查以确保该成员实际存在于指向对象的运行时类型中。
Meaning as long as you know that the upcast is safe before you do it it is guaranteed to work. That's why you should be using dynamic_cast
which returns nullptr
if unsuccessful.
意思是只要你知道在你做之前它是安全的,它可以保证工作。这就是为什么你应该使用dynamic_cast,如果不成功则返回nullptr。
Think of it this way if you have.
如果你有这种想法,就这么想吧。
Type * t1;
static_cast
of t1 to one of the classes deriving from it cannot be known at compile time, without in depth analysis of your program (which obviously it is not and should not be doing), so even if it ends up being correct you have no way of checking. dynamic_cast
does extra work at runtime to check if the conversion was successful hence the prefix dynamic.
如果没有深入分析你的程序(显然它不是也不应该这样做),在编译时就无法知道t1到其中一个类的static_cast,所以即使它最终是正确的你也没办法检查。 dynamic_cast在运行时执行额外的工作以检查转换是否成功,因此前缀是动态的。
#1
8
In the general case, converting a base to void to derived (or vice versa) via static casting is not safe.
在一般情况下,通过静态铸造将基础转换为空白到导出(反之亦然)是不安全的。
There will be cases where it will almost certainly work: if everything involved is a pod, or standard layout, and only single inheritance is involved, then things should be fine, at least in practice: I do not have chapter and verse from the standard, but the general idea is that the base in that case is guaranteed to be the prefix of the derived, and they will share addresses.
有些情况下它几乎肯定会起作用:如果涉及的所有内容都是一个pod或标准布局,并且只涉及单一继承,那么事情应该没问题,至少在实践中是这样的:我没有标准的章节和经文,但一般的想法是,在这种情况下,基数保证是派生的前缀,并且它们将共享地址。
If you want to start seeing this fail, mix in virtual
inheritance, multiple inheritance (both virtual
and not), and multiple implementation inheritance that are non trivial. Basically when the address of the different type views of this
differ, the void
cast from and back to a different type is doomed. I have seen this fail in practice, and the fact it can fail (due to changes in your code base far away from the point of casting) is why you want to be careful about always casting to and from void pointer with the exact same type.
如果你想开始看到这个失败,混合虚拟继承,多重继承(虚拟和非虚拟),以及多个非常重要的实现继承。基本上当不同类型视图的地址不同时,从不同类型转换回来的空隙注定要失败。我已经看到这在实践中失败,并且它可能失败的事实(由于代码库的变化远离投射点)是你为什么要小心总是使用完全相同类型的void指针进行强制转换。
#2
3
In general, no, it is not safe.
一般来说,不,它不安全。
Suppose that casting Derived*
directly to Base*
results in a different address (for example, if multiple inheritance or virtual inheritance is involved).
假设将Derived *直接转换为Base *会导致不同的地址(例如,如果涉及多个继承或虚拟继承)。
Now if you inserted a cast to void*
in between, how would the compiler know how to convert that void*
to an appropriate Base*
address?
现在,如果你在中间插入一个转换为void *,编译器将如何知道如何将该void *转换为适当的Base *地址?
If you need to cast a Derived*
to a void*
, you should explicitly cast the void*
back to the original Derived*
type first. (And from there, the cast from Derived*
to Base*
is implicit anyway, so you end up with the same number of casts, and thus it's not actually less any convenient.)
如果需要将Derived *强制转换为void *,则应首先将void *显式地转换回原始的Derived *类型。 (从那里,从Derived *到Base *的演员阵容无论如何都是隐含的,所以你最终会得到相同数量的演员阵容,因此它实际上并没有那么方便。)
#3
0
From the link you supplied yourself
从您自己提供的链接
9) A pointer to member of some class D can be upcast to a pointer to member of its base class B. This static_cast makes no checks to ensure the member actually exists in the runtime type of the pointed-to object.
9)指向某个类D成员的指针可以向上转换为指向其基类B成员的指针。此static_cast不进行检查以确保该成员实际存在于指向对象的运行时类型中。
Meaning as long as you know that the upcast is safe before you do it it is guaranteed to work. That's why you should be using dynamic_cast
which returns nullptr
if unsuccessful.
意思是只要你知道在你做之前它是安全的,它可以保证工作。这就是为什么你应该使用dynamic_cast,如果不成功则返回nullptr。
Think of it this way if you have.
如果你有这种想法,就这么想吧。
Type * t1;
static_cast
of t1 to one of the classes deriving from it cannot be known at compile time, without in depth analysis of your program (which obviously it is not and should not be doing), so even if it ends up being correct you have no way of checking. dynamic_cast
does extra work at runtime to check if the conversion was successful hence the prefix dynamic.
如果没有深入分析你的程序(显然它不是也不应该这样做),在编译时就无法知道t1到其中一个类的static_cast,所以即使它最终是正确的你也没办法检查。 dynamic_cast在运行时执行额外的工作以检查转换是否成功,因此前缀是动态的。