-1

Something is driving me crazy.

Assume we have these simple classes

public class Animal {
public void makeSound() {
    System.out.println("From Animal");
  }
}

public class Dog extends Animal {
public void makeSound() {
    System.out.println("From Dog");
}

public void flip() {
    System.out.println("Flipped");
}

public static void main(String[] args) {
  Animal a= new Animal();
  ((Dog)a).makeSound(); // Gives me an error at runtime.    

}

C++ code:

class Animal {
   public: 
          virtual void makeSound(){ cout<<" From Animal";}
};

class Dog : public Animal {
    public : void makeSound(){ cout<<" From Dog ";}
             void  flip() { cout<<"Flipped";}
};

 main() {
Animal *a = new Animal();
((Dog*)a)->makeSound(); // returns From animal 

  }

Why would it generate runtime error in Java, while it would work without a problem in C++ ?

Thank you

Fady Saad
  • 1,169
  • 8
  • 13
ZikoUdeM
  • 1
  • 2
  • It does "work without a problem". It is undefined behaviour due to C legacy. –  Jun 05 '17 at 04:05
  • 2
    a Dog is an Animal BUT an Animal is not necessarily a Dog – Scary Wombat Jun 05 '17 at 04:07
  • Possibly duplicates [explicit casting from super class to subclass](https://stackoverflow.com/questions/4862960/explicit-casting-from-super-class-to-subclass) with the same example – Fady Saad Jun 05 '17 at 04:08
  • Maybe some people would use the same example since it is everywhere on Java or C++ tutorial websites, but just playing with the same example in Java and C++, I found that I get an error in Java, while no error in C++ and it executes without a problem – ZikoUdeM Jun 05 '17 at 04:13
  • I repeat. The C++ code has problem. It is undefined behaviour. –  Jun 05 '17 at 04:15
  • @NickyC You mean the code I provided above ? Or in general ? Can we say that for Downcasting, both languages behave differently ? – ZikoUdeM Jun 05 '17 at 04:16
  • @NickyC Okay I google it and found that C/C++ has some weird things. Not only in downcast, but also in memory access etc.. So we can say that this problem is just a fault from C++ and not that I misunderstood something. – ZikoUdeM Jun 05 '17 at 04:22
  • Stop using the term "C/C++" –  Jun 05 '17 at 04:22
  • 2
    @ZikoUdeM It's not the fault of C++. C-style casts just don't do any runtime type checking. Use `dynamic_cast` if you want that. – Miles Budnek Jun 05 '17 at 04:23
  • @ZikoUdeM I repeat, it is C legacy. It is not a fault from C++. The fault is you mixing C-style cast with C++ polymorphic code. The fault is you choosing the wrong kind of casting. –  Jun 05 '17 at 04:33
  • The `((Dog*)a)` is equality with `static_cast(a)` in the c++ code,it's not check the run-time type,but the `((Dog)a)` will check the static type and run-time type at run-time,just like dynamic_cast in c++. – dabaicai Jun 05 '17 at 04:34
  • By doing `(Dog*)` you *explicitly* told the compiler not to complain even if you were doing something wrong. – Galik Jun 05 '17 at 04:40
  • So it works (but not really) in C++. It wouldn't work well in Object COBOL, would it? – Lew Bloch Jun 05 '17 at 04:46

2 Answers2

4

Your example does not work fine; it's behavior is undefined.

C++ has several different types of cast operations. The one you've used here is a C-style cast (technically it ends up doing a static_cast). C-style casts don't do any runtime type checking. It's up to the programmer to make sure the types involved make sense. If you want runtime type checking, use dynamic_cast. When using dynamic_cast with pointers, the cast will fail and return nullptr if the object isn't actually an instance of the type being cast to. When using references it will throw std::bad_cast.

class Animal {
public: 
    virtual void makeSound() { std::cout << "From Animal\n"; }
};

class Dog : public Animal {
public:
    void makeSound() { std::cout << "From Dog\n"; }
};

int main() {
    Animal *a = new Animal();
    Dog* d = dynamic_cast<Dog*>(a);
    if (d == nullptr) {
        std::cout << "cast failed\n";
    } else {
        d->makeSound();
    }
}

Live example

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52
0

Downcasting is only possible (in Java) if at some point in your code you reference the child class e.g.

Animal a = new Dog(); 
((Dog)a).makeSound();
anonymouse
  • 109
  • 2
  • 9
  • any explanation for the downvote would be greatly appreciated. thanks. – anonymouse Jun 05 '17 at 04:27
  • Normally this works because we now that a is a dog, but has Animal's methods only. While doing a downcast here, we get access to Dog's methods too. So makeSound() in both cases if called on a directly before and after downcasting will always return From Dog. P.S: I wouldn't down vote since I don't have a lot of reputation. But I appreciate your answer ! – ZikoUdeM Jun 05 '17 at 04:28