Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is 'object slice' needed in C++ ? Why it is allowed ? For more bugs?

Why C++ standard allow object slice ?

Please don't explain c++ object slice concept to me as I knew that.

I am just wondering what's the intention behind this c++ feature(object slice) design ?

To get novice more bugs?

Wouldn't it be more type safe for c++ to prevent object slice ?

Below is just a standard and basic slice example:

class Base{
public:
       virtual void message()
       {
               MSG("Base ");
       }
private:
    int m_base;
};

class Derived : public Base{
public:
       void message()
       {
               MSG("Derived "); 
       }
private:
       int m_derive;
};

int main (void)
{
    Derived dObj;

    //dObj get the WELL KNOWN c++ slicing below
    //evilDerivedOjb is just a Base object that cannot access m_derive
    Base evilDerivedOjb = dObj;  //evilDerivedObj is type Base
    evilDerivedOjb.message();    //print "Baes" here of course just as c++ standard says
}

Thanks in advance.

================================================================================= After reading all the answers and comments I think I should express my question better in the first place but here it comes:

When there is a is-a relationship(public inheritnace), instead of private/protected inheritance , you can do the following:

class Base{
public:
    virtual void foo(){MSG("Base::foo");}
};

class Derived : public Base{
public:
    virtual void foo(){MSG("Derived::foo");}
};

int main (void)
{
    Base b;
    Derived d;
    b = d;                      //1
    Base * pB = new Derived();  //2
    Base& rB = d;               //3

    b.foo();    //Base::foo
    pB->foo();  //Derived::foo
    rB.foo();   //Derived::foo
}

It's well known that only 2 & 3 works polymorphically while one is the infamous object slicing which produce nothing but a bug !

Note 1, 2 and 3 NEED is-a relationship to work.
If you are using private/protect inheritance, you will get compile error for all of them :

'type cast' : conversion from 'Derived *' to 'const Base &' exists, but is inaccessible
'type cast' : conversion from 'Derived *' to 'Base *' exists, but is inaccessible
'type cast' : conversion from 'Derived *' to 'Base &' exists, but is inaccessible

So my question(original intention) was to ask would it be better if c++ standard make 1 a compile error while keep allowing 2 and 3 ?

Hope I have expressed my question better this time.

Thanks

like image 384
RoundPi Avatar asked Sep 22 '11 14:09

RoundPi


1 Answers

It's allowed because of is-a relationship.

When you publicly1 derive Derived from Base, you're annoucing to the compiler that Derived is a Base. Hence it should be allowed to do this:

Base base = derived;

and then use base as it is. that is:

base.message(); //calls Base::message();

Read this:

  • Is-A Relationship

1. If you privately derive Derived from Base, then it is has-a relationship. That is sort of composition. Read this and this.

However, in your case, if you don't want slicing, then you can do this:

Base & base = derived;
base.message(); //calls Derived::message();

From your comment :

Wouldn't it better for C++ to prevent object slicing while only allow the pointer/reference to work for is-a relationshp ???

No. Pointer and Reference doesn't maintain is-a relationship if the base has virtual function(s).

 Base *pBase = &derived;
 pBase->message(); //doesn't call Base::message(). 
 //that indicates, pBase is not a pointer to object of Base type.

When you want one object of one type to behave like an object of it's base type, then that is called is-a relationship. If you use pointer or reference of base type, then it will not call the Base::message(), which indicates, pointer or reference doesn't have like a pointer or reference to an object of base type.

like image 191
Nawaz Avatar answered Sep 28 '22 06:09

Nawaz