class CBase { };
class CDerived: public CBase { };
CBase b;
CBase* pb;
CDerived d;
CDerived* pd;
pb = dynamic_cast<CBase*>(&d); // ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b); // wrong: base-to-derived
I know the "base to derived " cast is wrong. But what is the inside reason of it? What is logical reason inside? It's hard to remember this without more explanation I guess.
thank you!
First, CBase must be polymorphic in order for you to use dynamic_cast here (that is, it must have at least one virtual member function). Otherwise, you can't use dynamic_cast.
That said, the cast of &b to CDerived* is not wrong: pd will be a null pointer.
dynamic_cast has the useful property that when the cast fails (that is, if the object pointed to by the pointer isn't of the target type), it yields a null pointer. This allows you to test the actual type of an object. For example:
CBase b;
CDerived d;
CBase* pb = &b;
CBase* pd = &d;
CDerived* xb = dynamic_cast<CDerived*>(pb); // xb is null!
CDerived* xd = dynamic_cast<CDerived*>(pd); // xd points to d!
Your code would have been incorrect if you had used static_cast, since it casts without performing any runtime type check, which means there is no way to test whether the cast succeeded. If you ever need to cast down a class hierarchy and you don't know for certain whether the object is of the derived type to which you are trying to cast, you must use dynamic_cast.
For the derived to base conversion, you don't need (and generally don't want) to specify a cast explicitly at all:
CDerived d;
CBase *pb = &d; // perfectly fine
The base to derived cast isn't really wrong, though you'd generally prefer to avoid it. The reason behind that is fairly simple: a pointer to base could be pointing to an actual base object or anything derived from it. If you're going to down-cast like this, you generally need to check whether the conversion succeeded. In the specific case you've given, it won't succeed, so what gets assigned (the result of the dynamic_cast) will simply be a null pointer.
Most of the time, you'd prefer to specify a complete interface to objects of the class in the base class, so you rarely have much need for downcasts.
A derived class can have more "behaviors" than the base class. More member functions, more member data, etc. If you cast a base class to a derived class, and then try to treat it as a derived class, you'll try to make it do things it can't do. Because you are trying to make an instance of the base class do things only the derived class knows how to do.
pd is a pointer of type CDerived*. So, pd pointing object needs to have two sub-objects involved ( i.e., base & derived ). But with this statement -
pd = dynamic_cast<CDerived*>(&b);
Here ,pd is pointing to only a base sub-object. There is no partial way of pointing to sub-objects. So, it is wrong.
Related
I recently learned about upcasting and downcasting in C++. However I came up with a few questions during reading about downcasting. Say I have two classes
class Base {
public:
virtual void foo() {}
};
class Derived : public Base {
public:
Derived(int i) {
mem = i;
}
int mem;
};
My questions are the followings:
If I create an object Derived d(1), upcast to Base class, and then downcast it back to Derived class, is 'mem==1' preserved? Do I still have access to it? Assume pointer or reference is used so object slicing doesn't happen and dynamic_cast is used for downcasting.
When downcasting from Base class to Derived class, there will an additional member variable 'mem'. Is memory allocated for 'mem' during run-time (using dynamic_cast)? To what value will it be initialized to?
After some simple experiments, 1 seems to be true.
However for 2 it seems I can't start from a Base class pointer and dynamic_cast it into Derived class pointer as dynamic_cast returns null.
I read from another post saying "But the basic point of dynamic_cast is that it first checks that the pointee object is really of the derived type, and then returns a pointer to it, or returns a null pointer if the pointee object isn't actually of (or derived from) the requested target type."
Is this saying we can't actually start from the Base class and simply downcast it into Derived class, but rather the whole point of dynamic_cast is to "cast back" something that has been upcasted?
It depends; if you cast a Derived object to Base, the result is a new object created by omitting the fields that are not in the Base. However, if you cast a pointer to Derived (i.e. Derived*), the result is a pointer which points to the same object but whose type is Base*.
It depends; if you cast a Base object, you get a compile error unless you overload the typecast operator for doing such an operation (you have correctly observed that the values of the fields would otherwise be undefined). However, if you cast a Base* (a pointer) to Derived* (using dynamic_cast<Derived*>(p)), the result depends on the object the pointer points to. If it points to an instance of the Derived class (or its subclass), the result is a Derived* pointer to that object; otherwise, you get a nullptr pointer of type Derived*.
I was watching a video on youtube, how to do casting in c++?
As this is static casting I just want to know what will happen if I don't use pointers.
class Base{};
class Derived1: public Base {};
class Derived2: public Base{};
int main(){
Derived d1;
Derived d2;
Base *bp1=static_cast<Base*>(&d1);
Base *bp2=static_cast<Base*>(&d2);
Derived *d1p=static_cast<Derived1*>(bh2);
Derived *d2p=static_cast<Derived2*>(bp1);
return 0;
}
For example:
Base bp1=static_cast<Base*>(d1);
PS: I am sorry if this question doesn't make any sense.
Casting pointers (or references) doesn't do anything to the underlying objects, it just changes how you LOOK at something at the given address (when going through the casted pointer.) If the cast is invalid, of course your code will have undefined behavior.
Without pointers, you are actually modifying objects.
Derived d1;
Base b = d1; // makes a copy of just the "Base" part of d1
The above is ok, and needs no cast, but it's not a view of d1 looking like a Base. It is a sliced off copy of the base part of d1. "b" is an unrelated object, merely initialized by d. That is why it's called "slicing".
Casting an object to a pointer is non-sensical, unless your class has a conversion operator to that type, though that would be a generally terrible design:
struct Derived : Base {
explicit operator Base*() { return this; } // don't really do this, but it compiles
};
Given such a weird conversion operator, your cast would work, and it would call Derived::operator Base*. Because it's explicit, you would need the cast or the conversion would (usually) not happen. In general, I think you should think about this as mis-matching concepts. Pointers are not objects; they refer to them. Doing things to blur that is going to make your program very hard to reason about.
Why does static cast allow an upcast or downcast between pointers to objects derived or base as below, but in the case of casting between a char* and int* or vice versa int* to char*, there is a compilation error?
Casting between different pointers to objects is just as bad I believe.
// compiles fine
class Base {};
class Derived: public Base {};
Base * a = new Base;
Derived * bc = static_cast<Derived*>(a);
// Gives an invalid static cast error during compilation
char charVar = 8;
char* charPtr = &charVar;
int* intPtr = static_cast<int*>(charPtr);
C++ is strongly performance oriented. So as long as there is some use case for that you can gain performance, C++ will allow you to do it. Consider std::vector: Sure, there is the safe element access via function at, which does range checking for you. But if you know that your indices are in range (e. g. in a for loop), these range checks are just dead weight. So you additionally get the (less safe) operator[] which just omits these checks.
Similarly, if you have a pointer of type Base, it could, in reality, point to an object of type Derived. If in doubt, you would dynamic_cast from Base* to Derived*. But this comes with some overhead. But if you know 100% for sure (by whatever means...) what the sub class actually is, would you want this overhead? As there is a natural (even implicit!) way from Derived* to Base*, we want to have some low-cost way back.
On the other hand, there is no such natural cast between pointers of totally unrelated types (such as char and int or two unrelated classes) and thus no such low-cost way back (compared to dynamic_cast, which isn't available either, of course). Only way to transform in between is reinterpret_cast.
Actually, reinterpret_cast comes with no cost either, it just interprets the pointer as a different type – with all risks! And a reinterpret_cast even can fail, if instead a static_cast would have been required (right to prevent the question "why not just always use ..."):
class A { int a; };
class B { };
class C : public A, public B { };
B* b = new C();
C* c = reinterpret_cast<C*>(b); // FAILING!!!
From view of memory layout, C looks like this (even if hidden away from you):
class C
{
A baseA;
B baseB; // this is what pointer b will point to!
};
Obviously, we'll get an offset when casting between C* and B* (either direction), which is considered by both static_cast and dynamic_cast, but not by reinterpret_cast...
Why does static cast allow an upcast ...
There is no reason to prevent upcast. In fact, a derived pointer is even implicitly convertible to a base pointer - no cast is necessary (except in convoluted cases where there are multiple bases of same type). A derived class object always contains a base class sub object.
Upcasting is particularly useful because it allows runtime polymorphism through the use of virtual functions.
or downcast between pointers to objects derived or base as below
A base pointer may point to a base sub object of a derived object, as a consequence of an upcast. Like for example here:
Derived d;
Base *b = &d;
There are cases where you may want to gain access to members of the derived object that you know is being pointed at. Static cast makes that possible without the cost of run time type information.
It is not possible in general for the compiler to find out (at compile time) the concrete type of the pointed object (i.e. whether the pointer points to a sub object and if it does, what is the type of the container object). It is the responsibility of the programmer to ensure that the requirements of the cast are met. If the programmer cannot prove the correctness, then writing the static cast is a bug.
That's because what you're trying to do is a reinterpretation - for which there's a reinterpret_cast<> operator. static_cast<> for pointers is only used for down-casting:
If new_type is a pointer or reference to some class D and the type of expression is a pointer or reference to its non-virtual base B, static_cast performs a downcast. This downcast is ill-formed if B is ambiguous, inaccessible, or virtual base (or a base of a virtual base) of D. Such static_cast makes no runtime checks to ensure that the object's runtime type is actually D, and may only be used safely if this precondition is guaranteed by other means, such as when implementing static polymorphism. Safe downcast may be done with dynamic_cast.
See:
When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?
for a detailed discussion of when to use each casting operator.
I tried this which didn't work:
void Map::OnLMClick(short xPos, short yPos)
{
SObject* pSObject = pEditWindow->GetSelectedItem();
if (pSObject==SOTile)
{
/* Do */
I tried this as a test:
SObject* EditorWindow::GetSelectedItem()
{
return pSOTile[1]; //pSOTile[1] is a valid pointer, member of EditorWindow
}
SOTile class is a child of base class SObject. So, is it possible to create a Base* to get one of its child's* returned and then have the program react differently depending of what child it returned? If it is the case, how do I then have access to members of it's child that are not members of base?
If your types are polymorphic (i.e. if they have at least one virtual function), you can use dynamic_cast:
Base* pObject = get_object(); // May return a pointer to Derived
Derived* pDerived = dynamic_cast<Derived*>(pObject);
Notice, that dynamic downcasts are sometimes an indicator of bad design. Try to think if a better arrangement of virtual functions in your hierarchy would help.
Without knowing the concrete application domain, it is not possible for me to give more concrete advices.
dynamic_cast operator performs a special checking when a class is polymorhic.
SOTile* pSOTile = dynamic_cast<SOTile*>(pSObject);
if (pSOTile)
{
/* Do */
}
Since SOTile is a pointer to a type that derives from SObject, you should not need to cast at all, since the compiler should be able to automatically resolve an SObject pointer from the derived pointer and then compare the two SObject pointers together (the same way that you can assign a derived pointer to a base pointer without type-casting). Some compilers, like Borland's, support that just fine, eg:
class Base
{
};
class Derived : public Base
{
};
Derived *d = ...;
Base *b = ...;
if (b == d) // <-- compiles fine
However, if for whatever reason your compiler does not allow that, you can manually cast the derived pointer using static_cast (don't use dynamic_cast to cast the base pointer):
if (pSObject == static_cast<SObject*>(SOTile))
If SOTile is not a pointer to a type that derives from SObject, static_cast will fail at compile-time.
I wouldn't recommend to use dynamic_cast. Instead, you can implement that different behavior in different child class. Sometimes called as "template method" pattern
I have an object of a base class which is actually pointing to a derived class like this
Base *b = new Derived()
What I want to know, is it possible to pass the base class pointer by reference to some function which can cast the object back to Derived class. Something like this
Dummy_cast_fn(&b) // casts b to derived class
After calling Dummy_cast_fn, b should have a full copy of Derived class (no slicing).
Edit
I dont understand the part that there is no slicing since pointers are used. My problem is Derived class is returned from a function call to a shared library and I do not have access to .h file for the Derived. Only information I have is that Derived is based on Base class. I have access to Base.h so I can instantiate an object of Base but problem comes when I try to access the functions which are defined in Derived but not in Base. So I was wondering if I can typecast the Base to Derived type, then I will be able to access the function defined in Derived and not in Base.
As long as b is a pointer or reference to a Derived, you can always:
Down cast it to a Derived.
Treat it as a Base as long as you're using b.
Namely, what determines what you can do with b is its static type, in this case Base. However, since it actually points on a Derived, you can always downcast it. Yet, to use it as a Derived you must have a variable whose type is Derived as well.
So, if the purpose of Dummy_cast_fn is just to fix something in b - it's useless. If an object is sliced, nothing can fix it. But in your case, there's no slicing, since you're using pointers.
Edit according to the question's edit:
First, you're Derived object is not sliced. Let's get that off the table. You have a pointer to a complete Derived (assuming that's what you've been passed), but you only have access to its Base part when using the Base pointer. Now, you say you don't have the definition of Derived. This means you won't be able to downcast to that type, because the compiler doesn't know how it's defined. No casting will work here. There's no legal C++ way you can call that sum function if you don't have Derived's definition.
I do wonder why the author of Derived provided you its documentation without providing its definition. With this kind of polymorphism, the provider usually lets the user have some "interface", leaving the actual type as an internal implementation detail. If you can't use Derived because you don't have its definition, there's no point in letting you have its documentation.
You cannot change a Base* into a Derived*, but you can get a Derived* pointing to the object that a Base* is pointing to, using dynamic_cast:
Derived* d = dynamic_cast<Derived*>(b);
if (d) {
// cast was succesful
} else {
// cast failed,
// e.g. because b* does not point to a Derived* but some other derived type
}
You can't change the type of your Base* b, you can however create a new pointer
Derived* p = static_cast<Derived*>(b);
and use that. Once b is declared as Base* you can't modify its type. You can also use dynamic_cast also although this is slower and may not strictly be necessary (although I cannot say for certain - that depends on your requirements). And if you are correctly using virtual functions you may not even need to do any casting at all - that is one of the purposes of polymorphism