0

i'm wondering why this code works properly, i was convinced that casting wrong class would result in crash.

#include <iostream>
using namespace std;

class Base {
public:
    void MainFunc() {
        cout << "MainFunc called.\n";
    }
};
class DerivedOne : public Base {
public:
    void FirstDerived() {
        cout << "FirstDerived called.\n";
    }
};
class DerivedTwo : public Base {
public:
    void SecondDerived() {
        cout << "SecondDerived called.\n";
    }
};

int main() {
    Base* classesArray[2];
    classesArray[0] = new Base();
    classesArray[1] = new DerivedOne();
    ((DerivedTwo*)classesArray[1])->SecondDerived();
}

Is it okay to cast wrong derived class?

Alkyone
  • 21
  • 5
  • 8
    Undefined Behavior doesn't mean "crash". It means you can not know what will happen. – Drew Dormann Mar 08 '23 at 22:46
  • Please define *"works properly"*. – Bob__ Mar 08 '23 at 22:48
  • 1
    use `dynamic_cast` and check the return value – pm100 Mar 08 '23 at 22:50
  • 2
    _"Is it okay to cast wrong derived class?"_ No. That would be Undefined Behavior. – Drew Dormann Mar 08 '23 at 22:50
  • @OP *Is it okay to cast wrong derived class?* -- With C++, you cannot use proof-of-concept coding to determine if something is right or wrong. You know/learn through experience, reading C++ material, etc. that the behavior is undefined or not. – PaulMcKenzie Mar 08 '23 at 22:59
  • @DrewDormann Oh, so its undefined behavior, i thought it was somehow desired output, how is it even able to tell which function to call? – Alkyone Mar 08 '23 at 23:03
  • @Alkyone I think you're still unclear on what Undefined Behavior is. It's not "able to tell" anything. After Undefined Behavior, you are not in control. "It's" not in control. You simply don't know what's going to happen. What you observe does not matter. – Drew Dormann Mar 08 '23 at 23:05
  • @PaulMcKenzie Yeah, was trying to find out if its undefined behavior, but couldnt find anything, and was surprised that correct function was called. – Alkyone Mar 08 '23 at 23:05
  • @DrewDormann Thing is, even if classes are more complicated (more functions, variables etc.) desired function is still called, so to my understanding, even tho its undefined behavior, compiler did something to make it work. – Alkyone Mar 08 '23 at 23:11
  • Perhaps the most surprising thing about undefined behavior is that sometimes it appears to do what you want. That should make you very nervous. – Mark Ransom Mar 08 '23 at 23:11
  • @MarkRansom It kinda did, and now i want to know how why is it even possible to call "proper" function. – Alkyone Mar 08 '23 at 23:17
  • 1
    It calls the "correct" function because you told it what function to call and that function happens to not do anything with the data in the class. Remember, a function call `object.function()` is essentially the same as `function(&object)` at the assembly level. If the function never dereferences the pointer passed as `this` then it _probably_ won't notice that it doesn't point to the right thing. The behavior is undefined either way though; it could crash or corrupt unrelated data or send demons flying out of your nose still. – Miles Budnek Mar 08 '23 at 23:24
  • try adding a data field to TwoDerived (int x = 42 say) and try to print that variable in SecondDerived method. You will see why this is UB – pm100 Mar 08 '23 at 23:26
  • @MilesBudnek Okay, now its more clear, thank you. – Alkyone Mar 08 '23 at 23:32
  • @pm100 Well, it works fine. – Alkyone Mar 08 '23 at 23:34
  • 1
    Crashed on my machine. Because I run everything with `-fsanitize=undefined,null,address,bounds,bool,enum`. – Eljay Mar 08 '23 at 23:36
  • 1
    @Alkyone the lesson here is that you shouldn't try to observe what undefined behavior is going to do. You are doing that now, and every C++ developer eventually learns that they shouldn't do that. – Drew Dormann Mar 09 '23 at 00:27
  • The point of undefined behaviour is that the *standard* imposes no requirements (i.e. "undefined" is solely in context of what the standard says or doesn't say). Throw code with undefined behaviour at a toolchain (compiler, linker, etc) and *anything* may happen. A crash is one possible outcome. Running "correctly" (however you define "correctly") is a possible outcome. Reformatting your system hard drive (yes, I have seen this) is another possible outcome. Different outcomes can occur with different toolchains, or even phases of the moon - but all are correct *according to the standard*. – Peter Mar 09 '23 at 02:22
  • If you made `SecondDerived` a *virtual* function you'd probably get something closer to what you expected as undefined behavior. And the funny part is that neither behavior is more or less correct than the other. – Mark Ransom Mar 09 '23 at 03:03

0 Answers0