Polymorphism

V

Vinodh Kumar P

Why an object of a derived class can be treated as an object of its
base class when manipulated through POINTERS AND REFERENCES?Why this
polymorphic behaviour is not allowed for simply objects?

Kind Regards,
Vinodh Kumar P
 
J

Jesper Madsen

class A {
const A* getConstPtr(){ return this; };
virtual ~A(){};
};

class B: public A {
public:
int thisIsForSlicingIfCopied;
};

void someFunction(const A* anA,const A* anotherA){};

class C {
public:
C(){
someFunction(a.getConstPtr(),b.getConstPtr());
}
private:
A a;
B b;
};

the above will always work...
if you send a B as an A as an object, the B will be copied with sizeof(A).
When you make room for an A object and copies a B object to that space, a B
will be sliced down to an A...
I have seen no other language that supports this, except when all objects
are automagically passed as references...
 
R

Rolf Magnus

Vinodh said:
Why an object of a derived class can be treated as an object of its
base class when manipulated through POINTERS AND REFERENCES?Why this
polymorphic behaviour is not allowed for simply objects?

It's not really a matter of allowing it or not. Could you give an example of
how you would use it?
 
V

Vinodh Kumar P

#include <iostream>
using namespace std;

class Base
{
public:
virtual void FunctionX();
};

class Derived : public Base
{
public:
void FunctionX();

};

void Base::FunctionX()
{
cout << "Base::FunctionX()" << endl;
}

void Derived::FunctionX()
{
cout << "Derived::FunctionX()" << endl;
}

int main()
{
Base* aBasePtr = NULL;

// Invoke through objects
Base aBaseObject;
Derived aDerivedObject;

aBaseObject = aDerivedObject;
aBaseObject.FunctionX(); // Base FunctionX() is called
// My question is why we
don't have dynamic binding applied here?

// Invoke thorough pointers
aBasePtr = &aDerivedObject;
aBasePtr->FunctionX(); // Derived FunctionX() is called

return 0;
}

Output:
Base::FunctionX()
Derived::FunctionX()
 
J

Jonathan Mcdougall

Please don't top-post. Rearranged.
#include <iostream>
using namespace std;

class Base
{
public:
virtual void FunctionX();
};

class Derived : public Base
{
public:
void FunctionX();

};

void Base::FunctionX()
{
cout << "Base::FunctionX()" << endl;
}

void Derived::FunctionX()
{
cout << "Derived::FunctionX()" << endl;
}

int main()
{
Base* aBasePtr = NULL;

// Invoke through objects
Base aBaseObject;
Derived aDerivedObject;

aBaseObject = aDerivedObject;
aBaseObject.FunctionX(); // Base FunctionX() is called
// My question is why we
// don't have dynamic binding
// applied here?

Because at that point, there are no aDerivedObject anymore. The
assignment operator was called for aBaseObject and that operator took
the parts belonging to aDerivedObject's Base class and copied them.
aBaseObject is a Base object and will always be. Assiging something
else to it will only get the data part of the Base class. That's
*slicing* : an object loses the derived class' data.
// Invoke thorough pointers
aBasePtr = &aDerivedObject;
aBasePtr->FunctionX(); // Derived FunctionX() is called

Here, no copying or assignment takes place between the objects, you only
fiddle with pointer values. Both objects stay exactly the same in
memory, you only "trick" the system by using a pointer of another type.
The infrastructure in place takes care of forwarding calls to the
correct functions. You actually could use a wholly different type and
be able to call the functions through the pointer (not without crashing
of course) because you are not dealing with automatic objects, you are
dealing with memory addresses.


Jonathan
 
V

Vinodh Kumar P

Jonathan Mcdougall said:
Please don't top-post. Rearranged.
I am sorry.
Thanks for telling me what a top posting is.
I have realized.
Because at that point, there are no aDerivedObject anymore. The
assignment operator was called for aBaseObject and that operator took
the parts belonging to aDerivedObject's Base class and copied them.

aBaseObject = aDerivedObject;
aBaseObject.FunctionX(); // Base FunctionX() is called

Okay. By using these statements we can never get/accees "Derived" classes
functionality through "aBaseObject".
Then whats the purpose of allowing such assignment?
I am not clear about the OOAD principle behind the above assignment.
I feel such things should be prevented.
Please explain.
 
J

Jonathan Mcdougall

Vinodh said:
aBaseObject = aDerivedObject;
aBaseObject.FunctionX(); // Base FunctionX() is called

Okay. By using these statements we can never get/accees "Derived" classes
functionality through "aBaseObject".

It's more "get" than "access". To understand correctly, picture
yourself the operator= for the Base class :

Base &Base::eek:perator=(const Base& b)
{
this.data1 = b.data1;
this.data2 = b.data2;
...
}

That function is called with

Base b1
Derived b2; // or any type derived from Base or Base itself

b1 = b2;

which becomes

b1.operator=(b2);

As you see, only the parts Base is aware of are copied. That's normal,
because what Base works on are Base's also. Base's cannot know about
its derived class. Therefore, when do A = B, with A and B being two
automatic objects, A gets the parts of its type from B, but slices the rest.
Then whats the purpose of allowing such assignment?

I cannot think of an exact purpose right now since, as you say, we
usually are very careful not to allow slicing in our programs.
Actually, as soon as class polymorphism comes into play, we use
references and pointers.

The thing is, C++ is a low-level enough language not to disallow such
constructs. The thinking behind that is that you may need that feature
one day and you won't be able to replicate it. Something like muliple
inheritance, which you can avoid most of the time. But when you need
it, you really need it.
I am not clear about the OOAD principle behind the above assignment.
I feel such things should be prevented.

C++ has not the habit of forbidding things which can make sense in some
context. Slicing is considered a logic error (if you don't want it of
course), not a language error.


Jonathan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,781
Messages
2,569,615
Members
45,300
Latest member
RoryCarlso

Latest Threads

Top