2010-01-30 109 views
4

我有一个关于C++的问题,如何将基础对象分配给派生对象?或者如何将指向Base对象的指针分配给指向Derived对象的指针?如何将基础对象分配给派生对象

在下面的代码中,这两行是错误的。如何纠正?

#include <iostream> 
using namespace std; 
class A{ 
public: 
    int a; 
}; 

class B:public A{ 
public: 
    int b; 
}; 

int main(){ 
    A a; 
    B b; 
    b = a; //what happend? 
    cout << b.b << endl; 

    B* b2; 
    b2 = &a;  // what happened? 
    cout << b->b << endl; 
} 

回答

2

当一个对象位于堆栈上时,只能真正将相同类型的对象分配给另一个对象。它们可以通过重载的转换操作符或重载的赋值操作符进行转换,但是您在此处指定了转换。编译器不能自己做这样的转换。

A a; 
B b; 
b = a; 

在这种情况下,您试图将A分配给B,但A不是B,所以它不起作用。

A a; 
B b; 
a = b; 

这是一种时尚,但它可能不会是你期望的。你刚刚把你的B切成了B,B是A,所以赋值可以发生,但是因为它在堆栈上,它只是将a的一部分b分配给a。所以,你得到的是一个A.这不,尽管如果你真的想成为一个指定类型的对象到另一个,他们需要的指针,你从B.

分配的事实B中。

A* pa = NULL; 
B* pb = new B; 
pa = pb; 

This Works。现在pa指向pb,所以它仍然是B.如果你在A上有虚拟函数而B覆盖了它们,那么当你在pa上调用它们时,它们将调用B版本(非虚拟函数仍然会调用A版本)。

A* pa = new A; 
B* pb = pa; 

这是行不通的。 PA不点B,所以不能将其指定为PB必须指向B.仅仅因为B是A不意味着比A是B.

A a; 
B* pb = &a; 

这并未因为和上一个相同的原因工作。它恰好是这样的,A这次是堆栈而不是堆栈。

A* pa; 
B b; 
pa = &b; 

这是行不通的。 b是B是A,所以A可以指向它。虚拟功能将调用B版本,非虚拟功能将调用A版本。

所以,基本上,A *可以指向,因为B是A,B *不能指向A,因为它不是一个B.

1
b = a; //what happend? 

这是明显的违法 - A不是B,所以你不能做到这一点。

b2 = &a;  // what happened? 

同样在这里。

在任何情况下,编译器都不知道要分配给int b,因此他阻止你这么做。另一种方式(分配派生到基地)的作品,因为基地是一个派生的子集

现在,如果你想告诉我们,你想达到的是什么,我们可能会帮助你。

如果它的分配被称为是一个派生类的A的情况下,你可以做一个投:

A* a = new B(); 
B* b = dynamic_cast<B>(a); 

只要记住,如果a不是B然后将dynamic_cast将返回NULL。请注意,此方法仅适用于指针,原因是

+0

也适用于引用,在以下情况下抛出一个异常B的失败。但是,dynamic_cast似乎需要虚拟方法(例如向A添加虚拟析构函数) – UncleBens 2010-01-30 00:44:54

4

将基础对象分配给派生指针(或指向派生指针的基指针)是没有意义的,因此C++将尽其所能阻止您这样做。唯一的例外是当基指针真正指向的派生,在这种情况下,你可以使用动态转换:

base * p = new derived; 
derived * d = dynamic_cast <derived *>(p); 

在这种情况下,如果p其实指向一个基地,指针d将包含NULL。

+0

但是,如果类不包含任何虚函数,dynamic_cast似乎不被允许。您可以使用static_cast,但这意味着您要承担全部责任。 – UncleBens 2010-01-30 00:41:42

+0

@UncleBens如果基类不包含任何虚函数,我不得不问它为什么从它派生出来 - 如果你打算将它用于派生,它最后应该包含一个虚析构函数。 – 2010-01-30 09:46:36

+0

的确,继承数据的继承只是可疑的。在这种情况下,我实际上建议不要继承,给B一个成员,并提供一个构造函数,然后使用构造函数。 – UncleBens 2010-01-30 10:42:51

2

编译器不会允许这样的事情。即使你通过一些黑客行为来做到这一点,这样做也没有意义。将派生对象分配给基类的指针是有意义的,因为基类所能做的所有事情都可以派生出来。但是,如果允许相反的情况,如果您尝试访问派生的基础对象中定义的成员,该怎么办?您将尝试访问充满垃圾或无关数据的内存区域。

0

派生对象是一种Base对象,而不是其他方式。