简体   繁体   中英

Why C++ cannot initialize a variable of type “derived class” with an rvalue of type “super class”?

Please consider the code below:

class a
{
    int a1;

    public:
    a()
    {
        printf("foo1\n");
    }
};

class b : public a
{
    int a2;
    public:
    b()
    {
        printf("foo2\n");
    }
};
int main (int argc, const char * argv[])
{
    b *instance = new a();
    return 0;
}

It gives Error: Cannot initialize a variable of type "b*" with an rvalue of type "a*" Works fine when I write

a *instance = new b();

The output is:

foo1
foo2

Can someone please explain me the reason? I would be extremely grateful:)

Another thing, if I write

instance->~a();

above return 0; nothing extra happens. Is this because a constructor can be called only once?

b is an a .
a isn't a b .


You can put a instance of type Giraffe in a variable of type Animal .
However, you cannot put an instance of the Animal in a variable of type Giraffe (What if it's a Porcupine ?)

A derived class is, by definition, something that can do a superset of what a base class can do. The derived class can do everything the base class can, but not vice-versa. Therefore, it makes sense to treat a derived class as if it were the base class but not vice-versa. For example:

class Animal {
    void eat();
};

class Dog : public Animal {
    void bark();
}

It makes perfect sense to treat a Dog as a generic Animal , but there would be no reasonable thing for a generic Animal to do if ordered to bark .

Let's make this a little more concrete:

class Animal
{
    int a1;

    public:
    Animal()
    {
        printf("Animal\n");
    }
};

class Bat : public Animal
{
    int a2;
    public:
    Bat()
    {
        printf("bat\n");
    }
};
int main (int argc, const char * argv[])
{
    Bat *instance = new Animal();
    return 0;
}

Can you see now why this might not be valid? What you create with new Animal() can be any type of Animal. It may not be valid to assign it to a variable that is a Bat because it may not be a bat.

Since a is not a b , you can't assign a pointer to b to an object of type a .

Since b is an a , it is indeed working fine the other way around.

b is a type of a . However, a is not a type of b . If b contained additional members, then what happens when you try and access them if b really refers to an object of type a .

It's not a safe cast.

Remember this always, You cannot assign a base class object to a derived class pointer. [Derived class object] is a [Base class object]. The reverse is not true.

The problem is with "is a" relationship. Object of class a is not an object of class b so

b *instance = new a(); // won't work

would mean that you try to set a pointer to class b onto something that is not an object class b . At the same time you could do the opposite:

a* instance = new b(); //will work

since objects of class b are also objects of class a and so here you would set a pointer to class a onto something that is indeed an object of class a .

You can't substitute an a for a b because a doesn't have all of b 's functionality. Thus it makes no sense to make such an assignment.

For your second part, 99% of the time you say delete var to destroy something allocated with new instead of calling the destructor explicitly, which is an advanced topic.

Regarding the destructor -

If the static type of the operand is different from the dynamic type, then it's static type behaves as a base class and it's destructor must be virtual.

Also, pointer/reference of a derived class is type compatible with pointer/reference of base class. But the otherwise is not true. ( No transitive nature )

In your case -

a *instance = new b();  // This should be correct way.

The static type of instance is a* while the dynamic type is b* . So, a acts as a base class and it's destructor must be virtual .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM