views:

242

answers:

5

I just found that I am confused about one basic question in C++

class Base {

};

class Derived : public Base {

}

Base *ptr = new Derived(); 

What does it mean? ptr is pointing to a Base class or Derived class? At this line, how many memory is allocated for ptr? based on the size of Derived or Base?

What's the difference between this and follows:

Base *ptr = new Base();
Derived *ptr = new Derived();

Is there any case like this?

Derived *ptr = new Base();

Thanks!

+12  A: 

For Base *ptr = new Derived(); memory is allocated according to Derived class. ptr points to the object but the compiler is instructed to only "grant access" (visibility) to the members of the object that are declared in the Base class.

Of course the memory associated with the pointer ptr is the same i.e. independent of the object it is instructed to point to. Usually, the size of a "pointer object" is constant on a CPU architecture e.g. 32bits / 64bits (or smaller on embedded devices for example).

For Derived *ptr = new Base();: no, this is invalid.

Class Derived isn't just a class Base but is defined as deriving from Base: hence, a pointer instance to a Derived object instance can't be just assigned to an object instance of class Base.


You might consider perusing the very good Wikipedia contributions on Polymorphism and Inheritance.

jldupont
so what's the type of *ptr? Base or Derived? What's the advantage to make it as a pointer to Base?
skydoor
@skydoor: it relates to Polymorphism (see http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming): you could have different derived classes that share a base class.
jldupont
@skydoor-It's more flexible since a Base pointer can point to *any* object derived from a Base class.
John MacIntyre
+4  A: 

Polymorphism

ptr is a pointer; it has the same size regardless of what it points to.

Ignacio Vazquez-Abrams
+4  A: 

On a 32-bit system, 4 bytes of stack space are allocated for ptr. On a 64-bit system, it would be 8 bytes. (Assuming that the compiler doesn't decide to leave it in a register and not allocate any stack space at all).

The reason you can let a pointer to a Base point to a Derived is one of the basic principles of OOP - polymorphism. A Derived is a Base. You can stick it in anywhere a Base could be used.

Your last line (Derived *ptr = new Base();) is invalid because a Base is not a Derived.

Anon.
not necessarily stack-space.
jldupont
True. I was working under the assumption that this was a function-local variable.
Anon.
+1  A: 

Your question hits on one of the most important parts of object-oriented programming: polymorphism.

Derived is a subtype of Base. That means that everything that Base can do, Derived can also do. Often, Derived is more specific than Base: it works on a subset of what Base does, but it does that subset much better than what Base does.

Think about an example.

Think about writing a graphics program. You might have a class, ClosedShape, and a method inside it, fill(). It's possible to create a very generic method that can fill any closed shape... but usually, that method will take memory, and it might be slow.

You might have another class, Square. Now, filling squares is very easy and very fast: it's two nested for loops. Since Square does everything that ClosedShape does, it can inherit from ClosedShape.

Why is polymorphism important? Think about many different kinds of ClosedShape: triangles, hexagons, and so forth. If you want to fill all of them, just do:

for (i=0; i<num; i++) {
    cs[i].fill();
}

They all will use their own version of fill()!

Chip Uni
Nope. Inheritance has to do with method and field lookup. What you describe is Polymorphism.
Ignacio Vazquez-Abrams
You're right, Ignacio. I've changed my answer.
Chip Uni
+2  A: 

To understand the type system of C++, its important to understand the difference between static types and dynamic types. In your example, you defined the types Base and Derived and the variable ptr which has a static type of Base *.

Now when you call new Derived(), you get back a pointer with a static and dynamic type of Derived *. Since Derived is a subtype of Base this can be implicitly converted to a static type of Base * and assigned to ptr as the static types now match. The dynamic type remains Derived * however, which is very important if you call any virtual function of Base via ptr, as calling virtual functions is always based on the dynamic type of the object, not the static type.

Chris Dodd