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

3
请看下面的代码:

请考虑以下代码:

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*”的右值初始化类型为“b*”的变量。当我写成以下格式时就没问题:
a *instance = new b();

输出结果如下:
foo1
foo2

请问有人可以解释一下原因吗?非常感激 :)
另外,如果我写

,会发生什么?
instance->~a();

return 0; 上面没有任何额外的操作。这是因为构造函数只能被调用一次吗?


~a是析构函数,而不是构造函数。直接调用它们中的任何一个都很奇怪。 - Kate Gregory
语句 instance->~a(); 调用的是析构函数,而不是构造函数。通常情况下,您不需要手动执行此操作。对于使用 new 分配的对象,请使用 delete 运算符,例如 delete instance; - André Caron
我正在学习,想要澄清一些疑问。如果有冒犯到您,请原谅。感谢您的回答。 - jerrymouse
我看到我的问题被投了-1分。我想我冒犯了社区。再次道歉并感谢你们的回答。 - jerrymouse
你不应该显式地调用析构函数。唯一需要这样做的情况是当对象是使用放置 new 运算符构造的时候。 - Tamas Demjen
9个回答

6
让我们更具体一些:
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类型的变量可能无效,因为它可能不是蝙蝠。


6

b 是一个 a

a 不是一个 b


 

你可以将类型为 Giraffe 的实例放入类型为 Animal 的变量中。
但是,你不能将 Animal 类型的实例放入类型为 Giraffe 的变量中(如果它是一只 Porcupine 呢?)


4

派生类的定义是可以做基类能做的所有事情,而基类不能做派生类能做的事情。因此,将派生类视为基类是有意义的,但反过来则不行。例如:

class Animal {
    void eat();
};

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

Dog视为一种通用的Animal是完全合理的,但如果命令其bark,对于一种通用的Animal来说就没有合理的事情可做。


1

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

由于ba,因此反过来确实可以正常工作。


1

ba 的一种类型。然而,a 不是 b 的一种类型。如果 b 包含了额外的成员,那么当你尝试访问它们时,如果 b 真的指向了一个 a 类型的对象,会发生什么呢?

这不是一个安全的转换。


1

永远记住,你不能将一个基类对象赋值给一个派生类指针。 [派生类对象] 是一个 [基类对象]。 反过来则不成立。


0
关于解构函数:
如果操作数的静态类型与动态类型不同,则其静态类型将作为基类,其析构函数必须是虚拟的。
此外,派生类的指针/引用与基类的指针/引用类型兼容。但相反则不成立。(没有传递性)
在您的情况下 -
a *instance = new b();  // This should be correct way.

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


0
问题出在“是一个”关系上。类a的对象不是类b的对象,因此。
b *instance = new a(); // won't work

这意味着你试图将指针设置为 b 类,但却不是一个对象 b 类。同时,你也可以做相反的事情:

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

由于b类的对象也是a类的对象,因此在这里您将设置一个指向确实是a类对象的指针到a类上。


0

你不能用 a 替换 b,因为 a 没有 b 的所有功能。因此,这样的赋值没有意义。

至于第二部分,99% 的情况下,你会使用 delete var 来销毁使用 new 分配的内容,而不是显式地调用析构函数,这是一个高级话题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接