Skip to main content
gamedev.net
🔒 Locked

A* obj = new B (basic OOP question)

Started by load_bitmap_file Nov 17, 2004 at 2:52 PM 11 replies 1.7k views
Original Post
load_bitmap_file
load_bitmap_file
Given this:

class A
{
public:
//EDIT: No more memory leaks now :P
virtual ~A()
{
}
};

class B : class A
{
};

int main()
{
A* obj = new B;

return 0;
}



What exactly "is" obj? You can only access members declared in A but not B but if B redefines a function in A (assuming the function in A is virtual) then the B function is called. Is it "a A object that polymoprhically calls B functions"? [Edited by - load_bitmap_file on November 17, 2004 5:38:32 PM]
Alan Kemp
Alan Kemp
Quote:

Is it "a A object that polymoprhically calls B functions"?


No. Its a B object (it uses sizeof(B) memory), but you are "pretending" its an instance of A when you access it.

Imagine a stencil A with only half the alphabet. And a stencil B with the whole alphabet. You use B to write out the whole alphabet, but then place stencil A over the output. The underlaying representation is B, but you can only get to the bits they have in common.

My analogy breaks down at virtual functions. All they do really is "magically" replace functions with the version furthest down the inheritance tree.

After writing this Im not exactly certain what the question was :-) I'll post anyway as I think you were asking "how does inheritance/polymorphism work".

Alan
"There will come a time when you believe everything is finished. That will be the beginning." -Louis L'Amour
Qw3r7yU10p!
Qw3r7yU10p!
obj is a pointer to an object of, or derived from, type A.

obj in this case points to an object of type B, which is derived from type A.

You have a memory leak.
Fruny
Fruny
And to add to what petewood said, A's destructor should be virtual, or you'll be in a heap of trouble.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
TheBluMage
TheBluMage
obj is a pointer that points to a B object. However, the compiler can't be sure of that at compile-time, (the pointer itself is of the type A*, so all the compiler knows is that obj either points to an A object or one of its subclasses). Because of that, the compiler won't let you use any B members on an A pointer without an explicit cast. If your base class has at least one virtual function, you can use runtime checking to see if the object pointed to is, in fact, a certain subclass. For example:

#include <iostream>using namespace std;class MyBaseClass {    public:    virtual char* MyFunc();    char* OtherFunc();};char* MyBaseClass::MyFunc() { return "MyBaseClass"; }char* MyBaseClass::OtherFunc() { return "MyBaseClass"; }class ClassA : MyBaseClass {    public:    virtual char* MyFunc();    char* OtherFunc();};char* ClassA::MyFunc() { return "ClassA"; }char* ClassA::OtherFunc() { return "ClassA"; }class ClassB : MyBaseClass {    public:    virtual char* MyFunc();    char* OtherFunc();};char* ClassB::MyFunc() { return "ClassB"; }char* ClassB::OtherFunc() { return "ClassB"; }int main(int argc, char** argv) {        MyBaseClass* ptr = (MyBaseClass*) new ClassB;    //All the compiler knows is that ptr points to a MyBaseClass object        cout << ptr->OtherFunc() << endl;    //OtherFunc isn't virtual, so the compiler calls MyBaseClass's implementation        cout << ptr->MyFunc() << endl;    //MyFunc is virtual, so the compiler is able to determine which implementation to call at runtime        ClassA* ptrA = dynamic_cast<ClassA*>(ptr);    if(ptrA != NULL) cout << "Successful cast to: " << ptrA->OtherFunc() << endl;    else cout << "Unable to cast to ClassA" << endl;    //We try to cast ptr to a pointer to ClassA, but since the object pointed to is a ClassB, ptrA is now NULL        ClassB* ptrB = dynamic_cast<ClassB*>(ptr);    if(ptrB != NULL) cout << "Successful cast to: " << ptrB->OtherFunc() << endl;    else cout << "Unable to cast to ClassB" << endl;    //We try to cast ptr to a pointer to ClassB, and it works since the object pointed to is a ClassB, ptrB now points to the ClassB object    //Since the compiler knows that ptrB is pointing to a ClassB object, it can use ClassB's implementation of OtherFunc        delete ptr;    //Delete the object pointed to    //Note: it is highly recomended that base classes have virtual destructors, so that subclasses can clean up any memory that only they would allocate    }

Output:
MyBaseClass
ClassB
Unable to cast to ClassA
Successful cast to: ClassB


Dynamic casts will only work if your base class has at least one virtual function. As far as what implementation of a function gets called, if the function isn't virtual, the compiler will use the type of the pointer to determine which implementation to call; if the function is virtual, the compiler will use the virtual function tables to correctly identify which implementation should be called at runtime.
TheBluMage
TheBluMage
Wow, it took me a long time to write that. When I started nobody else had replied! [lol]
Qw3r7yU10p!
Qw3r7yU10p!
Quote:
Original post by TheBluMage
Wow, it took me a long time to write that. When I started nobody else had replied! [lol]

Rabbit punches

[Edited by - petewood on November 17, 2004 4:54:02 PM]
load_bitmap_file
load_bitmap_file
Thanks for the replies.

So.. would you call obj a A pointer to a B object?
ekrax
ekrax
i would call it a base class pointer (of type A).
MaulingMonkey
MaulingMonkey
The NATURE of obj is that it is a pointer, which points to one of the following:

1) An object of type A
2) An object that inherits from type A
3) NULL / 0 / Nothing.
4) Where an object of type A or inheriting from type A used to be (a "dangling pointer", dangerous to use because the object no longer exists)
5) Something else entirely (even more dangerous to use, results completely undefined if using it appropriately)

The VALUE of obj in your example is that it is a pointer to an object of type B.
Zahlman
Zahlman
Quote:
Original post by Fruny
And to add to what petewood said, A's destructor should be virtual, or you'll be in a heap of trouble.


Unless he creates a B with automatic storage; then he's in a stack of trouble. [grin]
Qw3r7yU10p!
Qw3r7yU10p!
Quote:
Original post by Zahlman
Quote:
Original post by Fruny
And to add to what petewood said, A's destructor should be virtual, or you'll be in a heap of trouble.


Unless he creates a B with automatic storage; then he's in a stack of trouble. [grin]


Funny, but wrong - yes I'm a pedant [grin]

If it's an automatic variable then the type will be correct when its destructor is called as the compiler has all the type information available. Along similar lines virtual functions can be inlined on automatic local variables.

You don't technically need a virtual destructor on a base class if you will never be deleting objects through the base class' pointer. The reason to make a base class destructor virtual is because it's the easiest way to avoid forgetting to put virtual destructors in derived classes when they are eventually really needed.
load_bitmap_file
load_bitmap_file
Quote:
Original post by Zahlman
Quote:
Original post by Fruny
And to add to what petewood said, A's destructor should be virtual, or you'll be in a heap of trouble.


Unless he creates a B with automatic storage; then he's in a stack of trouble. [grin]


Crazy word games :0

Thanks again to everyone.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.