简体   繁体   中英

Why does static_cast require pointers or references?

I recently had a situation where i had to use static_cast to cast a parent class to a child class, because i knew the object instance was that child class. I knew this based on an if condition.

Something like this:

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

My question is: Why does static_cast always require pointers? This did not work when i tried it with non-pointer variables. An exception seems to be primitive data types.

Is this because every pointer can be cast as a void*? Is that how static_cast works?

Edit: I forgot to mention that it works with references. So the question, as it is currently framed, is wrong. Reframing the question to "Why does static_cast require pointers or references?"

Why does static_cast always require pointers?

The operator static_cast doesn't require pointers, nor references.

C++ Standard n3337 § 5.2.9/4:

Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e) ; is well-formed , for some invented temporary variable t (8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The expression e is used as a glvalue if and only if the initialization uses it as a glvalue.

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

This did not work when i tried it with non-pointer variables.

For example? How you tried it? If you mean

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

then this is called slicing , what means p will only get those data from c which comes from parent class (how could object of class parent receive also child part, since child is addition to derived parent data?).

The reason is: it doesn't, it can be pointers or references. This has to do with the following problem:

 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.

Basically, you cannot make an INSTANCE of a based class with a derived class without risking slicing. But references/pointers are another matter. in that case, you are just interpreting how the memory pointed to is interpreted. Static cast doesn't actually do any operations in this case! Because of the way C++ classes are layed out (intentionally) everything that inherits from a Base class has t'she same memory layout from offset of 0 to sizeof(Base). Only after that do you add Derived stuff.

Why does static_cast always require pointers?

Well, not always. As you pointed out, the following is possible:

int i = static_cast<int>(3.14);

static_cast can also be used to convert between references, just like with pointers.

However, you have to take the following into account: When converting between two types, you can loose information. Suppose you have a class Animal and another class Dog that happens to inherit from it. What would this mean?

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

You're creating an Animal out of a Dog , but the Dog 's specific information will be thrown away. This is called slicing .

Casting between pointers usually just involves reinterpreting memory; the underlying object stays the same.

In essence static_cast<> always creates something new with type provided between the angle brackets. Consider:

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

Now the following code will not compile:

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

The reason is simple: this code tries to create new instance of derived and pass a base to its constructor. It would compile if derived had the constructor for that. For example:

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

But now you have a temporary that is going to be deleted immediately.

Obviously you don't want to create new derived instances here, but to reach the derived instance your base is part of. You need to create either a reference or a pointer to derived when performing the cast, and not a whole new instance of it. The following is going to work:

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

Now both dr and dp point to the same d above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM