C++ 为什么静态_cast需要指针或引用?

C++ 为什么静态_cast需要指针或引用?,c++,pointers,casting,static-cast,C++,Pointers,Casting,Static Cast,我最近遇到了一种情况,我必须使用static_cast将父类转换为子类,因为我知道对象实例就是那个子类。我是根据if条件知道的 大概是这样的: parent* foo; child* bar; if(foo is instance of child class) bar = static_cast<child*>(foo) 我的问题是: 为什么静态_cast总是需要指针?当我尝试使用非指针变量时,这不起作用。 一个例外似乎是基本数据类型 这是因为每个指针都可以转换为void*

我最近遇到了一种情况,我必须使用static_cast将父类转换为子类,因为我知道对象实例就是那个子类。我是根据if条件知道的

大概是这样的:

parent* foo;
child* bar;
if(foo is instance of child class)
   bar = static_cast<child*>(foo)
我的问题是: 为什么静态_cast总是需要指针?当我尝试使用非指针变量时,这不起作用。 一个例外似乎是基本数据类型

这是因为每个指针都可以转换为void*?静态_cast就是这样工作的吗


编辑:我忘了提到它与引用一起工作。因此,目前提出的问题是错误的。重新思考为什么静态强制转换需要指针或引用?

原因是:它不需要,它可以是指针或引用。这与以下问题有关:

 struct Base
 {

 };


 struct Derived : public Base
 {
   int A;
 };

 //sizeof(Base)==0
 //sizeof(Derived)==4
 Base B;
 Derived X;
 X.A = 10;
 B=X;//what happens to Derived::A? There is no space to put it. This is called slicing.

基本上,如果不冒切片的风险,就无法使用派生类创建基于类的实例。但引用/指针是另一回事。在这种情况下,您只是解释指向的内存是如何被解释的。在这种情况下,静态强制转换实际上不会执行任何操作!因为C++类是故意布局的,所以继承自基类的所有东西都有相同的内存布局,从0到sisifObScript的偏移量。只有在这之后,才能添加派生内容。

原因是:它没有,它可以是指针或引用。这与以下问题有关:

 struct Base
 {

 };


 struct Derived : public Base
 {
   int A;
 };

 //sizeof(Base)==0
 //sizeof(Derived)==4
 Base B;
 Derived X;
 X.A = 10;
 B=X;//what happens to Derived::A? There is no space to put it. This is called slicing.
基本上,如果不冒切片的风险,就无法使用派生类创建基于类的实例。但引用/指针是另一回事。在这种情况下,您只是解释指向的内存是如何被解释的。在这种情况下,静态强制转换实际上不会执行任何操作!因为C++类是故意布局的,所以继承自基类的所有东西都有相同的内存布局,从0到sisifObScript的偏移量。只有在这之后,你才能添加派生的东西

为什么静态_cast总是需要指针

运算符static_cast不需要指针,也不需要引用

C++标准n3337§5.2.9/4:

否则,表达式e可以显式转换为类型T 如果声明 T-te;对于一些发明的临时变量T8.5,它的格式是良好的。 这种显式转换的效果与执行 声明和初始化,然后使用临时 变量作为转换的结果。表达式e用作 glvalue当且仅当初始化将其用作glvalue时

当我尝试使用非指针变量时,这不起作用

比如说?你怎么试的? 如果你是说

child c;
parent p = static_cast<parent>( c);
这就是所谓的切片,这意味着p将只从c中获取来自父类的数据,父类的对象如何也能接收子部分,因为子类是派生父类数据的加法

为什么静态_cast总是需要指针

运算符static_cast不需要指针,也不需要引用

C++标准n3337§5.2.9/4:

否则,表达式e可以显式转换为类型T 如果声明 T-te;对于一些发明的临时变量T8.5,它的格式是良好的。 这种显式转换的效果与执行 声明和初始化,然后使用临时 变量作为转换的结果。表达式e用作 glvalue当且仅当初始化将其用作glvalue时

当我尝试使用非指针变量时,这不起作用

比如说?你怎么试的? 如果你是说

child c;
parent p = static_cast<parent>( c);
这就是所谓的切片,这意味着p将只从c中获取来自父类的数据,父类的对象如何也能接收子部分,因为子类是派生父类数据的加法

为什么静态_cast总是需要指针

嗯,不总是这样。正如你所指出的,以下是可能的:

int i = static_cast<int>(3.14);
您正在从狗身上创建一个动物,但狗的特定信息将被丢弃。这叫做切片

指针之间的转换通常只涉及重新解释内存;底层对象保持不变

为什么静态_cast总是需要指针

嗯,不总是这样。正如你所指出的,以下是可能的:

int i = static_cast<int>(3.14);
您正在从狗身上创建一个动物,但狗的特定信息将被丢弃。这叫做切片

指针之间的转换通常只涉及重新解释内存;基本对象保持不变。

本质上,静态类型转换总是使用尖括号之间提供的类型创建新对象。考虑:

class base { int x; };
class derived: public base { int y; };
现在,以下代码将无法编译:

base *b;
derived *d = &static_cast<derived>(*b);   // wrong
但是现在你有一个临时文件,它将被立即删除

显然,您不想为她创建新的派生实例 e、 但要到达派生实例,您的基础是其中的一部分。在执行强制转换时,您需要创建一个引用或指向派生对象的指针,而不是它的一个全新实例。以下措施将起作用:

derived d;
base *bp = &d;
base &br =  d;
derived &dr = static_cast<derived &>(br);
derived *dp = static_cast<derived *>(bp);
现在,dr和dp都指向上面相同的d。

本质上,静态投影总是通过在尖括号之间提供的类型创建新的内容。考虑:

class base { int x; };
class derived: public base { int y; };
现在,以下代码将无法编译:

base *b;
derived *d = &static_cast<derived>(*b);   // wrong
但是现在你有一个临时文件,它将被立即删除

显然,您不想在这里创建新的派生实例,但要到达您的基础所在的派生实例。在执行强制转换时,您需要创建一个引用或指向派生对象的指针,而不是它的一个全新实例。以下措施将起作用:

derived d;
base *bp = &d;
base &br =  d;
derived &dr = static_cast<derived &>(br);
derived *dp = static_cast<derived *>(bp);


现在,dr和dp都指向上面相同的d。

我还要补充一点,每当你必须这样做时,你都会向自己指出你的设计不好的地方!我还要补充一点,每当你必须这样做的时候,你都会向自己指出你的设计有问题!请举例说明当您尝试使用非指针变量时,哪些不起作用一般来说,必须从父对象强制转换到子对象是一种代码味道。您可能需要重新考虑您的设计。看看是否可以使用虚拟成员函数完成同样的任务。@Dima通常代码已经存在多年,因此重新考虑设计需要重写数千行(如果不是上万行)的代码。因此,反思往往不是一种选择。我遇到了一个K_的问题,指针和引用可以很好地转换,但转换非指针变量不会在无法重新思考或重写的代码上编译。我希望SO上的人能提供一些关于这个问题的信息。@K_看一看。这至少对我有帮助。请举个例子,当你尝试使用非指针变量时,什么不起作用一般来说,必须从父对象转换到子对象是一种代码味道。您可能需要重新考虑您的设计。看看是否可以使用虚拟成员函数完成同样的任务。@Dima通常代码已经存在多年,因此重新考虑设计需要重写数千行(如果不是上万行)的代码。因此,反思往往不是一种选择。我遇到了一个K_的问题,指针和引用可以很好地转换,但转换非指针变量不会在无法重新思考或重写的代码上编译。我希望SO上的人能提供一些关于这个问题的信息。@K_看一看。这至少对我有帮助,但这并不是你提到的静态强制转换最有趣的用法,因为这里静态强制转换不是实现功能所必需的。更有趣的用法是decltypee时的静态种姓;是一个有效的表达式。我最喜欢这个答案,因为它引用了标准。如果OP仔细阅读,那么他可能会明白为什么他尝试使用静态强制转换失败。嗨,我尝试了另一种方式…我尝试从父实例为子实例赋值。这没有意义,因为子对象比父对象大。这不是你提到的最有趣的静态强制转换使用,因为在这里,静态_cast不是实现功能所必需的。更有趣的用法是decltypee时的静态种姓;是一个有效的表达式。我最喜欢这个答案,因为它引用了标准。如果OP仔细阅读了这些内容,那么他可能会明白为什么他尝试使用静态强制转换失败。嗨,我尝试了另一种方式…我尝试从父实例向子实例赋值。这没有意义,因为子对象比父对象大。是的,也可以使用带有引用的静态强制转换。谢谢。是的,也可以使用带有引用的static_cast。谢谢。将派生类的继承标记为public,因为默认情况下是私有的,并且以您表示此代码的方式,它不适用于派生类:public base{int y;};。将派生类的继承标记为public,因为默认情况下它是私有的,并且以您表示此代码的方式,它不适用于派生类:public base{int y;};。