ceasif
ceasif

Reputation: 345

Is it valid to have base class attribute even though it is virtual when downcasting is done

Please refer to below code:

#define mPtr (static_cast<Dog*> (new(Animal)))

class Animal{
    public:
    virtual void talk(){cout<<"A";}
};
class Dog:public Animal{
    int test;
    public:
    void talk(){bark();}
    void bark(){
        test=0;cout<<test;
    }
};

int main() {

    mPtr->talk();
    mPtr->bark();
    return 0;
}

Output:

A0

Is it valid or an undefined behaviour to have base class talk() is executing?

Upvotes: 0

Views: 59

Answers (2)

Useless
Useless

Reputation: 67772

Come on, let's unpack that code and show why it is wrong. Hiding your sins in a macro doesn't make them go away.

int main() {
    Animal a;
    Dog *dog = &a;
    dog->talk();
}

Try that. Does it compile? If not, what does the compiler say? If the compiler says that assignment doesn't make sense, why would it be a good idea to coerce it?

The only case where downcasting is safe is where you know the dynamic type is correct (from context, or by using typeid or something else), or where you use dynamic_cast to test whether or not your object has the expected subtype.

Your un-checked downcast to the wrong subtype is indeed undefined behaviour.


OK, I see the confusion is actually about what static_cast means, rather than about polymorphism. So, let's look at the documentation.

static_cast < new_type > ( expression )

Your code (downcasting) is the second case described:

2) If new_type is a pointer or reference to some class D and the type of expression is a pointer or reference to its non-virtual base B, static_cast performs a downcast. ... Such static_cast makes no runtime checks to ensure that the object's runtime type is actually D, and may only be used safely if this precondition is guaranteed by other means

The bold part (my formatting) is the reason your cast is illegal.

It's useful to note that this is only the case because you're casting a pointer (although it's the same for references) - the pointer is not the object. Casting a pointer doesn't alter the object or create a new one, it just provides a different view on the existing object.

Conversely, see the first case described:

1) If there is an implicit conversion sequence from expression to new_type, or if overload resolution for a direct initialization of an object or reference of type new_type from expression would find at least one viable function, then static_cast<new_type>(expression) returns the imaginary variable Temp initialized as if by new_type Temp(expression);

So, if you added a constructor

Dog::Dog(Animal const &) {}

which creates a Dog from an Animal, you could write

Animal a;
Dog dog = static_cast<Dog&>(a);

and it would be fine - this creates a Dog from a (which is not the same object as a).

Upvotes: 3

user7860670
user7860670

Reputation: 37600

It is straight undefined behavior. You can only cast to derived class using static_cast when you are 100% sure that pointer points to the object of that derived class. For safe conversion in class hierarchy dynamic_cast can be used instead. And in this case dynamic_cast<Dog*>(new Animal) would return nullptr indicating that object pointed to is not of Dog class.

Upvotes: 6

Related Questions