开发者

Declaring pointer to base and derived classes

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

class Base {

};

class Derived : public Base {

}

Base *ptr = new Derived(); 

What doe开发者_如何学JAVAs 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!


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.


Polymorphism

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


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.


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.


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()!


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.


A Derived object is appended to the end of the Base object, so the prefix [in bits] of Derived is actually a Base, so there is no problems to assign a Derived* object to a Base* variable. It is perfectly safe to access any of Base's fields/methods of the Derived object.

However - the oposite is not true. If you assign the address of the Base* to a Derived* variable and then access one of the fields of Derived [which is not in Base] you will get out of the allocated space.

Typing reasoning:
Also note that a value can be assigned to a variable only if it is of the correct type without casting [c++ is static typing langauge]. Since Derived is a Base, Derived* is a Base* - so this is not conflicting, but the other way around is not true.

I highly recommend to read the comment to understand the logic as well

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜