C ++转换为派生类

时间:2011-03-15 14:36:33

标签: c++ inheritance

我如何投射到派生类?以下方法都会出现以下错误:

  

无法从BaseType转换为DerivedType。没有构造函数可以采取   源类型或构造函数重载决策是不明确的。

BaseType m_baseType;

DerivedType m_derivedType = m_baseType; // gives same error

DerivedType m_derivedType = (DerivedType)m_baseType; // gives same error

DerivedType * m_derivedType = (DerivedType*) & m_baseType; // gives same error

4 个答案:

答案 0 :(得分:123)

这样想:

class Animal { /* Some virtual members */ };
class Dog: public Animal {};
class Cat: public Animal {};


Dog     dog;
Cat     cat;
Animal& AnimalRef1 = dog;  // Notice no cast required. (Dogs and cats are animals).
Animal& AnimalRef2 = cat;
Animal* AnimalPtr1 = &dog;
Animal* AnimlaPtr2 = &cat;

Cat&    catRef1 = dynamic_cast<Cat&>(AnimalRef1);  // Throws an exception  AnimalRef1 is a dog
Cat*    catPtr1 = dynamic_cast<Cat*>(AnimalPtr1);  // Returns NULL         AnimalPtr1 is a dog
Cat&    catRef2 = dynamic_cast<Cat&>(AnimalRef2);  // Works
Cat*    catPtr2 = dynamic_cast<Cat*>(AnimalPtr2);  // Works

// This on the other hand makes no sense
// An animal object is not a cat. Therefore it can not be treated like a Cat.
Animal  a;
Cat&    catRef1 = dynamic_cast<Cat&>(a);    // Throws an exception  Its not a CAT
Cat*    catPtr1 = dynamic_cast<Cat*>(&a);   // Returns NULL         Its not a CAT.

现在回顾你的第一个陈述:

Animal   animal = cat;    // This works. But it slices the cat part out and just
                          // assigns the animal part of the object.
Cat      bigCat = animal; // Makes no sense.
                          // An animal is not a cat!!!!!
Dog      bigDog = bigCat; // A cat is not a dog !!!!

你应该很少需要使用动态演员 这就是我们有虚拟方法的原因:

void makeNoise(Animal& animal)
{
     animal.DoNoiseMake();
}

Dog    dog;
Cat    cat;
Duck   duck;
Chicken chicken;

makeNoise(dog);
makeNoise(cat);
makeNoise(duck);
makeNoise(chicken);

我能想到的唯一原因是你是否将对象存储在基类容器中:

std::vector<Animal*>  barnYard;
barnYard.push_back(&dog);
barnYard.push_back(&cat);
barnYard.push_back(&duck);
barnYard.push_back(&chicken);

Dog*  dog = dynamic_cast<Dog*>(barnYard[1]); // Note: NULL as this was the cat.

但是如果你需要将特定的物体投射回狗身上,那么你的设计就会出现根本性的问题。您应该通过虚拟方法访问属性。

barnYard[1]->DoNoiseMake();

答案 1 :(得分:7)

dynamic_cast应该是你要找的东西。

编辑:

DerivedType m_derivedType = m_baseType; // gives same error

上面似乎试图调用赋值运算符,它可能没有在DerivedType类型上定义并接受BaseType类型。

DerivedType * m_derivedType = (DerivedType*) & m_baseType; // gives same error

您在这里是正确的路径,但dynamic_cast的使用将尝试安全地转换为提供的类型,如果失败,将返回NULL。

在此处继续使用内存,请尝试此操作(但请注意,当您从基类型转换为派生类型时,强制转换将返回NULL):

DerivedType * m_derivedType = dynamic_cast<DerivedType*>(&m_baseType);

如果m_baseType是指针并实际指向DerivedType类型,那么dynamic_cast应该可以工作。

希望这有帮助!

答案 2 :(得分:5)

您无法将基础对象强制转换为派生类型 - 它不属于该类型。

如果你有一个指向派生对象的基类型指针,那么你可以使用dynamic_cast来转换该指针。例如:

DerivedType D;
BaseType B;

BaseType *B_ptr=&B
BaseType *D_ptr=&D;// get a base pointer to derived type

DerivedType *derived_ptr1=dynamic_cast<DerivedType*>(D_ptr);// works fine
DerivedType *derived_ptr2=dynamic_cast<DerivedType*>(B_ptr);// returns NULL

答案 3 :(得分:2)

首先 - 向下转换的先决条件是您要投射的对象属于您要投射的类型。使用dynamic_cast进行转换将在运行时检查此条件(假设转换对象具有一些虚函数)并在失败时抛出bad_cast或返回NULL指针。编译时强制转换不会检查任何内容,如果此先决条件不成立,则只会导致未定义的行为 现在分析你的代码:

DerivedType m_derivedType = m_baseType;

这里没有铸造。您正在创建类型为DerivedType的新对象,并尝试使用m_baseType变量的值对其进行初始化。

下一行不是更好:

DerivedType m_derivedType = (DerivedType)m_baseType;

在这里,您要创建一个用DerivedType值初始化的m_baseType类型的临时类型。

最后一行

DerivedType * m_derivedType = (DerivedType*) & m_baseType;
如果BaseTypeDerivedType的直接或间接公共基类,

应该编译。无论如何它有两个缺陷:

  1. 您使用弃用的C风格演员表。这种演员阵容的正确方法是 static_cast<DerivedType *>(&m_baseType)
  2. 实际类型的转换对象不是DerivedType(因为它被定义为BaseType m_baseType;所以使用m_derivedType指针会导致未定义的行为。