Amol Sharma
Amol Sharma

Reputation: 1591

Assignment of object of one type to the other type

In the Code Below there are Two Classes. One Object of type two is created and then it is assigned to pointer of class one.

On Calling the out function, the out function of the class one is called.

#include<iostream>
using namespace std;

class one
{
    public :
        void  out()
        {
            cout<<"one ";
        }
};

class two
{
    public : 
        void out()
        {
            cout<<"two ";
        }
};

int main()
{ 
    two dp[3];
    one *bp = (one *)dp;
    for (int i=0; i<3;i++)
    (bp++)->out();
}    

OUTPUT

one one one

Output according to me should be two instead of one. When we created the object of type two, the memory location of that object contained the address of the function of out of class two, then why on assignment, out of class one is called ?

EDIT - moreover even if we change the name of function in class two, the output is not changed.

Upvotes: 2

Views: 203

Answers (3)

Geoff Reedy
Geoff Reedy

Reputation: 36011

Since your out() method is not declared virtual it is dispatched on the static type of the object not the runtime type of the object.

Also, there is no subtype relation between the two classes so it is incorrect to assign the pointers in this way.

Upvotes: -3

John Dibling
John Dibling

Reputation: 101456

The output on your machine may have been "one one one" but it could just as easily have blown up, gone & gotten you ice cream, or launched the missiles. Your code evokes Undefined Behavior.

class one
/*...*/

class two
/*...*/

Note that one and two are completely unrelated classes. You are not deriving two from one, or vice versa. They are entirely different types.

Because of this...

two dp[3];
one *bp = (one *)dp;
for (int i=0; i<3;i++)
    (bp++)->out();

This code evokes Undefined Behavior*. bp does not point to an object of type one, it points to an object of type two. You cannot cast pointers in this way given the above code.

(* Note: The Undefined Behavior was when you tried to call a one method when the object was actually a two. Casting itself does not evoke Undefined Behavior.)

This cast syntax you are using, (one *)dp is a C-style cast, which in this instance boils down to the equivilant of reinterpret_cast<one*>(bp);. It would be best to use reinterpret_cast when that's what you really intend to do, if for no other reason than to write self-documenting code.

If you really are trying to get a one* from a two*, you have two options.

  1. Create an inheritence hierarchy so that you can cast without evoking UB
  2. Create a conversion operator so that you can construct a one from a two or vice versa.

In your case, since you're looping over an array of one objects and trying to execute two methods through those pointers, your best bet is probably #1 above.

class one
{
    public :
        virtual void  out()
        {
            cout<<"one ";
        }
};

class two : public one
{
    public : 
        void out()
        {
            cout<<"two ";
        }
};

Now your loop will work and the code will emit "two two two" instead of whatever random behavior you actually saw.

Upvotes: 1

molbdnilo
molbdnilo

Reputation: 66371

It's not uncommon for a novice to assume that all C++ member functions "belong" to an object.
As you noticed, they don't.

Conceptually - the precise procedure is a compiler implementation detail - your out member functions are transformed into "free" functions that look like these:

void one_out(one* this) { cout << "one"; }
void two_out(two* this) { cout << "two"; }

For non-member functions, that's all that's needed.

When the compiler sees

  (bp++)->out();

it knows that bp is a pointer to one (it doesn't know that you lied), and so it calls

one_out(bp++);

because that's what compilers do.

Upvotes: 4

Related Questions