Eric
Eric

Reputation: 1

Raw pointer of std::shared_ptr returns base instead of derived

class Base
{
  bool a;
};

class Derived : public Base
{
  bool b;
};

void main()
{
  std::shared_ptr<Base> base(new Derived());
}

So in this example the raw pointer of shared_ptr will point to an instance of Base, NOT Derived. Which I do not understand.

class Base
{
  virtual void foo() {}
  bool a;
};

class Derived : public Base
{
  virtual void foo() {}
  bool b;
};

void main()
{
  std::shared_ptr<Base> base(new Derived());
}

But in this case the raw pointer of shared_ptr does point to Derived? I'm sure I'm missing something. can someone explain to me why this is happening?

Upvotes: 0

Views: 314

Answers (2)

James Kanze
James Kanze

Reputation: 153929

First, the use of std::shared_ptr here is a red herring. In this case, both std::shared_ptr and a raw pointer behave exactly the same. In both cases, the expression new Derived() returns a Derived* which points to the entire object. And in both cases, using it to initialize a pointer to Base, be it a raw pointer or any reasonably designed smart pointer will cause the Derived* to be converted to a Base*, which points to the Base sub-object in the Derived. The Derived object still exists, however, and can be accessed in several different ways: via virtual functions, by using std::dynamic_cast if Base is polymorphic (has at least one virtual function), by using std::static_cast if you're 100% sure that the pointed to object actually is a Derived, and probably some others I've not thought of. In your first case, only the last is possible, since in the first, Base is not polymorphic. In both of your examples, however, the pointer points to a Base, which is a subobject of a larger Derived.

There are some differences between std::shared_ptr and a raw pointer. For example, in your first example, replacing std::shared_ptr<Base> with Base* and manually deleting through the pointer will result in undefined behavior; std::shared_ptr has extra complications to avoid this. (But the complications aren't without their drawbacks. Give Base a virtual destructor, as it should have, and then make the destructor of Derived private, for whatever strange reason, and your first example won't compile.)

Upvotes: 1

Photon
Photon

Reputation: 3222

In the first example, the classes do not have a virtual table, since there are no virtual functions. This means, that since the shared_ptr expects a static type of Base, it will store a Base. The second case also stores a Base, but the existence of a virtual table allows you to see that the dynamic type of the object is Derived.

Upvotes: 2

Related Questions