C ++ приведение к производному классу - PullRequest
44 голосов
/ 15 марта 2011

Как я могу привести к производному классу?Все приведенные ниже подходы дают следующую ошибку:

Невозможно преобразовать из 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 ]

123 голосов
/ 15 марта 2011

Думайте так:

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();
7 голосов
/ 15 марта 2011

dynamic_cast должен быть тем, что вы ищете.

EDIT:

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 должен работать.

Надеюсь, это поможет!

5 голосов
/ 15 марта 2011

Нельзя привести базовый объект к производному типу - это не тот тип.

Если у вас есть указатель базового типа на производный объект, вы можете использовать этот указатель с помощью 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
2 голосов
/ 15 марта 2011

Прежде всего - предварительным условием для понижения является тот тип объекта, к которому вы применяете.Приведение с помощью 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;

должен компилироваться при условии, что BaseType является прямым или косвенным публичным базовым классом DerivedType.В любом случае у него есть два недостатка:

  1. Вы используете устаревший каст в стиле C.Правильный способ для таких приведений:
    static_cast<DerivedType *>(&m_baseType)
  2. Фактический тип приведенного объекта не является DerivedType (так как он был определен как BaseType m_baseType;, поэтому любое использование указателя m_derivedType приведет к неопределенномуповедение.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...