-1

Noob to C++. I countered a weird issue when playing with inheritance in C++. I have a Parent class, and 2 child class that inherit Parent class.

#include <iostream>
#include <memory>

class Parent {
  public:
    Parent() {}
};

class Child1: public Parent {
  public:
    int param1;
    Child1(int param): Parent() {
      param1 = param;
    }
};

class Child2: public Parent {
  public:
    int param2;
    Child2(int param): Parent() {
      param2 = param;
    }
};

int main() {
  std::shared_ptr<Parent> obj = std::make_shared<Child1>(123);

  std::cout << std::static_pointer_cast<Child2>(obj)->param2 << std::endl;
  // output 123 and no run time error, wut?

  return 0;
}

As you can see, although obj is initialized with Child1's constructor, it can still be cased to Child2. Event param2 has the same value as param1.

What's going on here? Is there a term for this kind of behavior? Is this special to shared_ptr?

Thanks a lot!

Daiwei
  • 40,666
  • 3
  • 38
  • 48
  • Yes, the duplicate doesn't discuss shared_ptr, but that is immaterial. The shared_ptr is just an indirection step to doing this static_cast. Consult the duplicate for a thorough explanation. – StoryTeller - Unslander Monica Oct 21 '18 at 06:05
  • @StoryTeller It is related, but not really a duplicate (assuming OP does not know `std::static_pointer_cast` is performing a `static_cast` downcast). – Acorn Oct 21 '18 at 06:09
  • @Acorn - There's a big hint that it does. And I beg to differ, the shared_ptr is just a red herring. – StoryTeller - Unslander Monica Oct 21 '18 at 06:10
  • @StoryTeller For you/me, indeed. For beginners searching information about `std::static_pointer_cast`, not really. A comment with a link to the other question is good enough, but an actual answer explaining the entire reasoning is better. – Acorn Oct 21 '18 at 06:16

1 Answers1

1

According to [util.smartptr.shared.cast], std::static_pointer_cast returns:

shared_ptr<T>(r, static_cast<typename shared_ptr<T>::element_type*>(r.get()))

This means that, effectively, you are performing an static_cast from Parent * to Child2 *. That is fine.

However, in this case, the object you are casting, obj, has runtime type Child1 *, so you end up with undefined behavior, according to [expr.static.cast]p11:

A prvalue of type “pointer to cv1 B”, where B is a class type, can be converted to a prvalue of type “pointer to cv2 D”, where D is a class derived from B, if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. (...) If the prvalue of type “pointer to cv1 B” points to a B that is actually a subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the behavior is undefined.

Acorn
  • 24,970
  • 5
  • 40
  • 69
  • "You wouldn't be able to do a normal static_cast from one to the other" is this because I'm using smart pointer? what does it mean by "normal"? is there a abnormal one? thanks! – Daiwei Oct 21 '18 at 05:50
  • 1
    @Daiwei No, the problem is trying to do a `static_cast` to an unrelated type, i.e. an invalid downcast. See e.g. [Downcasting using the 'static_cast' in C++](https://stackoverflow.com/questions/6322949/) for details. – Acorn Oct 21 '18 at 05:56
  • @Daiwei I have edited the answer to give you more (formal) details. – Acorn Oct 21 '18 at 06:08