为什么向下转型需要类型转换才能工作?

时间:2011-03-05 18:22:09

标签: c++

为什么我们在进行向下转换时需要进行类型转换?

假设我有一个基类B和一个派生类D.现在我分别创建两个实例b,d,B,D。如果没有类型转换,为什么d = b是不可能的,即使d是b的所有内容。然而,反过来(即b = d)是可能的。

class B  
{  
    /* body */  
};  
class D : public B  
{  
    /* body */   
};

void f()  
{  
    B b;  
    D d;

    b = d;       /* OK */
    d = b;       /* Not OK */

return;  
}  

5 个答案:

答案 0 :(得分:3)

这是合乎逻辑的。每个派生对象都是基础对象,因此向上转换是自动的。但是每个基础对象都不是派生的,因此你需要明确地转换它。

见这个简单的例子:

struct Fruit {};    
struct Apple : Fruit {};

Apple apple;
Fruit fruit;
fruit = apple; //ok - automatic - since apple is fruit  (see "object slicing")
apple = fruit; //error - not automatic - since fruit is necessarily apple!

查看错误和行号:

http://ideone.com/JnLc2


但是,如果以下列方式重载operator=

struct Apple : Fruit 
{ 
    Apple & operator = (const Fruit &); 
};

然后不需要显式转换。你可以写

apple = fruit; //alright - assignment (not construction)

请参阅:http://ideone.com/IGbFI

现在,如果你添加这个:

struct Apple : Fruit 
{ 
    Apple(const Fruit &); 
};

然后你可以写

Apple apple  = fruit ; //ok - construction ( not assignment)

请参阅:http://ideone.com/muQc0

答案 1 :(得分:2)

从项目的角度考虑它。说class B是一个球,class D是一个躲避球。然后对于所有躲避球,它们都是球(因此对于所有class D它们都是class B)。但是,并非所有球都是躲避球,因此class B不一定是class D。这只是一个快速解释,并没有给出任何真正的技术原因 - 但我希望这有助于理解!

的问候,
丹尼斯M。

答案 2 :(得分:0)

'b'是'd'功能的子集。将'b'转换为'd'时,您只能访问'B'成员和方法,因此这是安全的。然而,将'd'转换为'b'可能会导致问题,因为'D'是'B'的超级集合。

这是一个更相关的例子:

struct B
{
  int m_variable;
};

struct D: public B
{
  int m_other_variable;
};


void function()
{
   B b;
   D *d;

   d = (D*)&b; //not a safe cast!

   d->m_other_variable = 101; // this isn't inside 'B' but beyond it. What this will //probably do is set the pointer 'd' to 101 but it might not: defined behaviour land!


}

'D'的实例包含'm_variable'和'm_other_variable',并且大小至少为8个字节。另一方面,'B'的实例仅包含'm_variable',且大小至少为4个字节。

答案 3 :(得分:0)

考虑这个逻辑:

D是B。

但B不一定是D。

因此,如果您可以将B类型传递给D,则无法保证。

D可能还有其他未在Base中实现的东西(D工作所需的更多方法,B就是没有)。

因此,当你使用Downcast时,你会让C ++将B的内存区域视为D ...这可能会导致运行时错误。

答案 4 :(得分:0)

由于D来自B,因此D具有B的所有功能以及它自己的一些功能。现在,当您将类型B的对象分配给D时,生成的对象无法完全构造,因为无法知道如何填充D的功能值。

考虑以下示例扩展 -

B级 {
  int memberOfB;
};
D类:公共B
{
  int memberOfD; };

现在D有两个成员,memberOfB(通过继承)和memberOfD(自己的成员) 当您尝试d = b时,可以分配memberOfB的值,但编译器无法将任何值分配给memberOfD,从而导致错误。

如果您确实需要此功能,则必须重载赋值运算符以处理此方案。