为什么static_cast需要指针或引用?

时间:2014-04-03 17:10:14

标签: c++ pointers casting static-cast

我最近遇到过一种情况,我不得不使用static_cast将父类强制转换为子类,因为我知道对象实例是那个子类。我根据if条件知道这一点。

这样的事情:

parent* foo;
child* bar;
if(foo is instance of child class)
   bar = static_cast<child*>(foo)

我的问题是: 为什么static_cast总是需要指针?当我用非指针变量尝试它时,这不起作用。 一个例外似乎是原始数据类型。

这是因为每个指针都可以转换为void *吗?这是static_cast的工作原理吗?

编辑:我忘了提及它适用于引用。因此,目前陷害的问题是错误的。重新定义问题&#34;为什么static_cast需要指针或引用?&#34;

4 个答案:

答案 0 :(得分:5)

  

为什么static_cast总是需要指针?

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

C ++标准版n3337§5.2.9/ 4:

  

否则,表达式e可以显式转换为类型T.   如果声明,使用static_cast<T>(e)形式的static_cast   T t(e);对于一些发明的临时变量t(8.5),结构良好。   这种显式转换的效果与执行相同   声明和初始化然后使用临时   变量作为转换的结果。表达式e用作   glvalue当且仅当初始化将它用作glvalue。

parent* foo;
child* bar;
if(foo is instance of child class)
   bar = static_cast<child*>(foo)
  

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

例如?你是怎么试的? 如果你的意思是

child c;
parent p = static_cast<parent>( c);

然后这称为切片,这意味着p只会从父类中获取来自c的那些数据(类父类的对象如何也接收到子元素,因为子元素是派生父元素的加法数据?)。

答案 1 :(得分:0)

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

 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.

基本上,您不能使用派生类创建基类的INSTANCE而不会有切片的风险。但引用/指针是另一回事。在这种情况下,您只是解释如何解释指向的内存。在这种情况下,静态强制转换实际上不执行任何操作!由于C ++类的布局方式(故意)从Base类继承的所有内容都有相同的内存布局,从0到sizeof(Base)的偏移量。只有在那之后才添加派生的东西。

答案 2 :(得分:0)

  

为什么static_cast总是需要指针?

嗯,并非总是如此。正如您所指出的,以下是可能的:

int i = static_cast<int>(3.14);

static_cast也可用于在引用之间进行转换,就像使用指针一样。

但是,您必须考虑以下因素:在两种类型之间进行转换时,您可能会丢失信息。假设您有一个类Animal,而另一个类Dog碰巧从它继承。这意味着什么?

Dog d;
Animal a = static_cast<Animal>(d);

您正在Animal中创建Dog,但Dog的具体信息将被丢弃。这称为切片

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

答案 3 :(得分:0)

本质上static_cast<>总是创建一些新的类型,在尖括号之间提供类型。考虑:

class base { int x; };
class derived: public base { int y; };

现在以下代码无法编译:

base *b;
derived *d = &static_cast<derived>(*b);   // wrong

原因很简单:此代码尝试创建derived的新实例,并将base传递给其构造函数。如果derived具有构造函数,它将编译。例如:

class derived: public base
{
  int y;
  derived(const base &){}
};

但是现在你有一个临时删除的临时文件。

显然,您不希望在此处创建新的derived实例,但要到达您的基础所属的派生实例。在执行转换时,您需要创建引用或指向derived的指针,而不是它的全新实例。以下是可行的:

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

现在drdp都指向上面的d