5

Is this static_cast downcast valid?

// non-virtual, may be non-trivially copyable
struct Base{
    int m_object;
};

// Derived class have only non-virtual functions
struct A : Base{
    void arggh(){
        std::cout << "Arrghh " << m_object;
    }
};

int main() {
    Base base{190};
    A& a = static_cast<A&>(base);
    a.arggh();
    return 0;
}

I mean, CREATE base class, and then cast to derived.

Live

tower120
  • 5,007
  • 6
  • 40
  • 88
  • 6
    No, an object of type `Base` is not an object of type `A` – UnholySheep Nov 15 '17 at 15:04
  • just curious, why would you do this? – miradham Nov 15 '17 at 15:14
  • You should do the invert Base* b = new A(); and all the methods that you have that are common should be "virtual". That is how you handle it, that is the reason to have a interface that specifies the contract. – Lefsler Nov 15 '17 at 15:14
  • @miradham Wel...... I found myself in situation where I start writing Proxy object, which I could easily recreate(it have only 1 ptr). Then I need Proxy + some data... And then I thought what a heck... :) Hard to explain in two words. – tower120 Nov 15 '17 at 15:19
  • @appleapple not exactly - this is non-virtual classes. – tower120 Nov 15 '17 at 15:22

3 Answers3

11

static_cast for performing downcast does not perform any safety checks. Since it's possible for a Base& to be referencing an instance of A, the cast proceeds and since it's NOT actually referencing an A, we enter undefined behavior territory*.

A dynamic_cast on the other hand is safer. It will perform a check and throw an exception in the case of reference casting, or return nullptr in the case of pointer casting.

However, since your base class lacks any virtual functions, dynamic_cast is impossible, so you'd need to modify it with at least a virtual destructor:

class Base{
public:
    int m_object;
    virtual ~Base()=default;
};

Now if we tried to cast:

A* a = dynamic_cast<A*>(&base);
if (a)
    a->arggh();
else
    std::cout << "null\n";

Our output would be

null


*Relevant standardese can be found in [expr.static.cast]:

[for a cast like static_cast<D&>(b) where b is an instance of a base class for D], If the object of type “cv1 B” is actually a base class subobject of an object of type D, the result refers to the enclosing object of type D. Otherwise, the behavior is undefined.

Relevant standardese at [expr.dynamic.cast]

The value of a failed cast to pointer type is the null pointer value of the required result type. A failed cast to reference type throws an exception of a type that would match a handler of type std::bad_cast

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
AndyG
  • 39,700
  • 8
  • 109
  • 143
1

No.

Not all Base objects are of type A1, although the converse is true, and a static_cast would work in that direction.


1Another translation unit might have a class that inherits from Base.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
0

Not at all.

Let's say Base is represented in memory by this block [--] and A is [--+], here you can see that A contains a part Base (with the little '-').

When you are creating a Base you have your [--] and then you are casting it to A which means that you are saying it's in fact [--+] BUT the memory after [--] does not correspond to [--+]

As you may understand with this example, you can cast A to Base because [--+] contains [--]

Light
  • 308
  • 2
  • 6