为什么C ++不能用“超类”类型的右值初始化“派生类”类型的变量?

时间:2011-07-15 14:28:20

标签: c++ oop

请考虑以下代码:

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;
}

它给出错误:无法初始化类型为“a *”的rvalue的“b *”类型的变量 我写的时候工作正常

a *instance = new b();

输出结果为:

foo1
foo2

有人可以解释一下原因吗?我将非常感激:))

另一件事,如果我写

instance->~a();

以上return 0;没有额外的事情发生。这是因为构造函数只能被调用一次吗?

9 个答案:

答案 0 :(得分:6)

ba a不是b


您可以将Giraffe类型的实例放入Animal类型的变量中 但是,您无法将Animal的实例放入Giraffe类型的变量中(如果它是Porcupine会怎么样?)

答案 1 :(得分:4)

根据定义,派生类可以做基类可以做的超集。派生类可以执行基类可以执行的所有操作,但反之亦然。因此,将派生类视为基类是有意义的,反之亦然。例如:

class Animal {
    void eat();
};

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

Dog视为通用Animal非常有意义,但如果订购到Animal,通用bark就没有合理的理由。

答案 2 :(得分:4)

让我们更具体一点:

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;
}

你现在能看到为什么这可能无效吗?使用new Animal()创建的内容可以是任何类型的动物。将它分配给Bat的变量可能无效,因为它可能不是蝙蝠。

答案 3 :(得分:1)

由于a不是b,因此您无法将指向b的指针指定给a类型的对象。

由于b是一个a,所以它确实可以正常工作。

答案 4 :(得分:1)

b是一种a。但是,a不是b的类型。如果b包含其他成员,那么当b真正引用a类型的对象时,如果您尝试访问它们会发生什么。

这不是一个安全的演员。

答案 5 :(得分:1)

始终记住这一点,您不能将基类对象分配给派生类指针。 [派生类对象]是[基类对象]。 反之则不然。

答案 6 :(得分:0)

问题在于“是一种”关系。 class a的对象不是class b的对象

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

意味着您尝试将指针class b设置为不是对象class b的内容。与此同时,你可以做相反的事情:

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

因为class b的对象也是class a的对象,所以在这里你要设置指向class a的指针到确实是class a的对象的东西。

答案 7 :(得分:0)

您无法用a替换b,因为a没有b的所有功能。因此,做出这样的任务毫无意义。

对于你的第二部分,99%的时间你说delete var要销毁用new分配的东西,而不是明确地调用析构函数,这是一个高级主题。

答案 8 :(得分:0)

关于析构函数 -

如果操作数的静态类型与动态类型不同,那么它的静态类型表现为基类,它的析构函数必须是虚拟的。

此外,派生类的指针/引用与基类的指针/引用类型兼容。但其他情况并非如此。 (没有传递性质)

在你的情况下 -

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

instance的静态类型为a*,而动态类型为b*。因此,a充当基类,它的析构函数必须是虚拟