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
精彩评论