Приведение С++ в производный класс
Как я могу передать производный класс? Приведенные ниже подходы дают следующую ошибку:
Невозможно преобразовать из 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
Ответы
Ответ 1
Подумайте вот так:
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();
Ответ 2
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.
Идти в память здесь, попробуйте это (но заметьте, что cast вернет NULL при выводе из базового типа в производный тип):
DerivedType * m_derivedType = dynamic_cast<DerivedType*>(&m_baseType);
Если m_baseType был указателем и фактически указал на тип DerivedType, тогда dynamic_cast должен работать.
Надеюсь, это поможет!
Ответ 3
Вы не можете применить базовый объект к производному типу - он не относится к этому типу.
Если у вас есть указатель базового типа на производный объект, вы можете использовать этот указатель с помощью 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
Ответ 4
Прежде всего - предпосылкой для понижающего является то, что объект, который вы выполняете, относится к типу, на который вы производите. Casting with dynamic_cast проверяет это условие во время выполнения (при условии, что у кастового объекта есть некоторые виртуальные функции) и бросает bad_cast
или возвращает NULL
указатель на сбой. Сроки компиляции не будут проверять что-либо и будут вести поведение tu undefined, если это условие не выполняется.
Теперь проанализируем ваш код:
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
. В любом случае, у него есть два недостатка:
- Вы используете устаревший стиль C-стиля. Правильный способ для таких отливок -
static_cast<DerivedType *>(&m_baseType)
- Фактический тип литого объекта не принадлежит DerivedType (поскольку он был определен как
BaseType m_baseType;
, поэтому любое использование указателя m_derivedType
приведет к поведению undefined.