C++ cast to derived class
Think like this:
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.
Now looking back at your first statement:
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 !!!!
You should very rarely ever need to use dynamic cast.
This is why we have virtual methods:
void makeNoise(Animal& animal)
{
animal.DoNoiseMake();
}
Dog dog;
Cat cat;
Duck duck;
Chicken chicken;
makeNoise(dog);
makeNoise(cat);
makeNoise(duck);
makeNoise(chicken);
The only reason I can think of is if you stored your object in a base class container:
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.
But if you need to cast particular objects back to Dogs then there is a fundamental problem in your design. You should be accessing properties via the virtual methods.
barnYard[1]->DoNoiseMake();
In C++, why does casting to reference of derived type work?
Because the implicit conversion from A
to B
doesn't exist, and you didn't define an explicit one either.
Reference casting, on the other hand, is valid because it is allowed for inherited types. More precisely, you can cast both ways between different classes in the same inheritance hierarchy. Same goes for pointers. The related concept is called polymorphism, if you'd like some pointers for further study.
Do note, however, that it only makes sense for an object that is of type B
to be cast to B
. E. g.:
B b;
A& aRef = B; // equivalent of A& ref = (A&)B;
B& bRef = (B&)aRef;
What you did will fail at runtime as soon as you try to access some data or method of B
that does not exist in A
. Because your actual object is A
, not B
.
Upcasting (from an descendant to an ascendant) is always safe because any object of a class that inherits the base class is a valid base object. The downcasting, however, is dangerous for the exact reason I explained above, and should never be done using a C-style cast. Instead, use dynamic_cast
:
B b;
A& aRef = B;
B& bRef = dynamic_cast<B&>(aRef);
dynamic_cast
uses RTTI (run-time type information) to validate the operation and will throw an std::bad_cast
exception if the conversion is not valid. This is unlike dynamic_cast
ing pointers, in which case the cast returns nullptr
instead of throwing an exception.
Cast base class object to derived class
Use dynamic_cast:
Animal& animal = getAnimalFromStack();
if(Dog *d = dynamic_cast<Dog*>(&animal))
{
// You have a dog pointer, use *d ...
}
Is it safe to cast a class to a derived class that just adds additional functions?
No, this isn't safe. The behaviour of the program is undefined.
Static casting to a derived type is safe only when the dynamic type of the object is that derived type (or a further derived type).
Can we convert a base class pointer to a derived class pointer without knowing its real type?
The thing is: You need to know the type of each variable at compile time. Hence you cannot have a magical function f
that takes an A* a
and returns either B*
or C*
based on the runtime information of the actual type of the object pointed to by a
. Even for the the following example the function B::f
will be called but the return type will be of type A*
since this is determined at compile time.
#include <iostream>
struct A {
virtual A* get_ptr() { std::cout << "A!\n"; return this; }
virtual ~A() {}
};
struct B: A {
B* get_ptr() { std::cout << "B!\n"; return this; }
};
void f(A*) { std::cout << "But here A!\n";}
void f(B*) { std::cout << "But here B!\n";}
int main() {
B b;
A* a = &b;
f(a->get_ptr());
}
Will print B!
(since it is virtual) and then call the A*
(since the compiler assumes that a->get_ptr()
returns a A*
) overload.
What you can do is:
- Switch on an enum that you store in the object that corresponds to its type.
- Trial and error with
dynamic_cast
.
Addendum: You will probably not need to cast a pointer to the object you have to the actual type of the object, since you can (as done above) just call the virtual functions and those will call the functions belonging to the actual type of your object. Hence, when you think that you need to do the cast as you described, think again, you probably will not need it.
If you still think you need it, reconsider your design decisions, you are probably doing something very weird.
how to cast a const base class pointer into the derived class
When you do
int res1 = ((Scalar<int>*)base)->get();
you do what is called a c-style cast. This works because c-style casts don't do any checking and ignore the casting away of const
. They just cast the source type to the destination regardless of any consequences.
On the other hand static_cast
actually checks what you are doing and sees you are trying to cast the constness of base
away. That isn't allowed by any cast except const_cast
so you get an error. We could use that here to get rid of the constness but that isn't needed. What you can do is just cast to a const Scalar<int>*
using
int res2 = static_cast<const Scalar<int>*>(base)->get();
Convert base class to derived class
No, there's no built-in way to convert a class like you say. The simplest way to do this would be to do what you suggested: create a DerivedClass(BaseClass)
constructor. Other options would basically come out to automate the copying of properties from the base to the derived instance, e.g. using reflection.
The code you posted using as
will compile, as I'm sure you've seen, but will throw a null reference exception when you run it, because myBaseObject as DerivedClass
will evaluate to null
, since it's not an instance of DerivedClass
.
c++ design: cast from base to derived class with no extra data members
Here is why I would not use this technique:
It is a violation of the Standard and causes the behavior to be undefined. It is probably true that this works nearly all the time, but you can't rule out problems in the future. Compilers have been seen to make use of undefined behavior in optimizations, much to the disadvantage of the unsuspecting programmer. And you can't predict when and under what circumstances this will happen.
You can't guarantee that neither you nor a team mate will ever add some data members to the derived type. Your class hierarchy will grow and more code will be added over time; at some point it may not be obvious to you or another programmer that adding an innocent data member to the derived type (even temporarily, perhaps for some debugging purpose) can spell disaster.
There are clean and legal alternatives, for example using wrappers based on references:
#include <iostream>
struct Elem
{ };
struct ElemWrapper
{
Elem &elem_;
ElemWrapper(Elem &elem) : elem_(elem)
{ }
};
struct ElemWrapper1 : ElemWrapper
{
using ElemWrapper::ElemWrapper;
void foo()
{ std::cout << "foo1" << std::endl; }
};
struct ElemWrapper2 : ElemWrapper
{
using ElemWrapper::ElemWrapper;
void foo()
{ std::cout << "foo2" << std::endl; }
};
int main()
{
Elem e;
ElemWrapper1(e).foo();
return 0;
}
c++ - converting a base class pointer to a derived class pointer
You must change the base type to be polymorphic:
class Base {
public:
Base() {};
virtual ~Base(){};
};
To cast from some supertype to some derived type, you should use dynamic_cast
:
Base *b = new Derived<int>(1);
Derived<int> *d = dynamic_cast<Derived<int> *>(b);
Using dynamic_cast
here checks that the typecast is possible. If there is no need to do that check (because the cast cannot fail), you can also use static_cast
:
Base *b = new Derived<int>(1);
Derived<int> *d = static_cast<Derived<int> *>(b);
Related Topics
How to Initialize Base Class Member Variables in Derived Class Constructor
Unresolved External Symbol _Imp_Fprintf and _Imp_Iob_Func, Sdl2
How to Parse Space-Separated Floats in C++ Quickly
Best Way to Store Currency Values in C++
How to Forward Declare an Inner Class
Why Will Std::Sort Crash If the Comparison Function Is Not as Operator ≪
Smart Pointers (Boost) Explained
How to Combine Hash Values in C++0X
How to Change Mode from C++98 Mode in Dev-C++ to a Mode That Supports C++0X (Range Based For)
How to Efficiently Perform Double/Int64 Conversions With Sse/Avx
What Is the Meaning of the Term "Free Function" in C++
What Are the Correct Link Options to Use Std::Thread in Gcc Under Linux
Check If a String Contains a String in C++
Difference Between String and Char[] Types in C++
What Is the Purpose of Std::Launder