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.
Related
I'm confused about assigning the base object of a derived class. Say I have a type:
class Base {
// stuff omitted for brevity
}
and a derived class
Derived : public Base {
// stuff omitted
}
and I have a situation that arises like this:
Derived = Base;
Is this possible? What is this operation called? How would I do such a thing?
Thanks for your help.
This is a perfectly ordinary user-defined assignment that looks enough like "slicing", treating a base class as if it were a member, to confuse the unwary. But it's not slicing. For the situation you have, the two classes might as well not be related, and you define the assignment that way.
struct d : b {
d &operator=(const b &b_) { /*do the work here*/; return *this; }
};
You might be able to use the base class's copy-assignment operator, or you might not:
struct dx : b {
dx &operator=(const b &b_)
{
this->b::operator=(b_);
// more work
return *this;
}
};
but the compiler gives this no special treatment, it's the same as any function call.
You should almost never assign a base class object to a derived class object, because then a derived object is only partly assigned which may not be consistent. But there are times that you may need to cast a pointer of a base class object to a pointer of a derived class object
Base *pb = new Derived;
..
Derived *pd = dynamic_cast<Derived*>(pb);
This is used when you want to identify the exact type of the object pointed by a base pointer(but actually pointing to the drived object, like in this example). Usually you should avoid this because it's time-consuming, and it's not a good design.
This is called object slicing and it is usually a bad thing. A Derived class is a Base class with more stuff. So when you assign a Derived object to a Base object, what should happen to the extra stuff? The operation doesn't make logical sense.
Ok, I was reading through this entry in the FQA dealing about the issue of converting a Derived** to a Base** and why it is forbidden, and I got that the problem is that you could assign to a Base* something which is not a Derived*, so we forbid that.
So far, so good.
But, if we apply that principle in depth, why aren't we forbidding such example?
void nasty_function(Base *b)
{
*b = Base(3); // Ouch!
}
int main(int argc, char **argv)
{
Derived *d = new Derived;
nasty_function(d); // Ooops, now *d points to a Base. What would happen now?
}
I agree that nasty_function does something idiotic, so we could say that letting that kind of conversion is fine because we enable interesting designs, but we could say that also for the double-indirection: you got a Base **, but you shouldn't assign anything to its deference because you really don't know where that Base ** comes, just like the Base *.
So, the question: what's special about that extra-level-of-indirection? Maybe the point is that, with just one level of indirection, we could play with virtual operator= to avoid that, while the same machinery isn't available on plain pointers?
nasty_function(d); // Ooops, now *d points to a Base. What would happen now?
No, it doesn't. It points to a Derived. The function simply changed the Base subobject in the existing Derived object. Consider:
#include <cassert>
struct Base {
Base(int x) : x(x) {}
int x;
};
struct Derived : Base {
Derived(int x, int y) : Base(x), y(y) {}
int y;
};
int main(int argc, char **argv)
{
Derived d(1,2); // seriously, WTF is it with people and new?
// You don't need new to use pointers
// Stop it already
assert(d.x == 1);
assert(d.y == 2);
nasty_function(&d);
assert(d.x == 3);
assert(d.y == 2);
}
d doesn't magically become a Base, does it? It's still a Derived, but the Base part of it changed.
In pictures :)
This is what Base and Derived objects look like:
When we have two levels of indirection it doesn't work because the things being assigned are pointers:
Notice how neither of the Base or Derived objects in question are attempted to be changed: only the middle pointer is.
But, when you only have one level of indirection, the code modifies the object itself, in a way that the object allows (it can forbid it by making private, hiding, or deleting the assignment operator from a Base):
Notice how no pointers are changed here. This is just like any other operation that changes part of an object, like d.y = 42;.
No, nasty_function() isn't as nasty as it sounds. As the pointer b points to something that is-a Base, it's perfectly legal to assign a Base-value to it.
Take care: your "Ooops" comment is not correct: d still points to the same Derived as before the call! Only, the Base part of it was reassigned (by value!). If that gets your whole Derived out of consistency, you need to redesign by making Base::operator=() virtual. Then, in the nasty_function(), in fact the Derived assignment operator will be called (if defined).
So, I think, your example does not have that much to do with the pointer-to-pointer case.
*b = Base(3) calls Base::operator=(const Base&), which is actually present in Derived as member functions (inc. operators) are inherited.
What would happen then (calling Derived::operator=(const Base&)) is sometimes called "slicing", and yes, it's bad (usually). It's a sad consequence of the sheer omnipresence of the "become-like" operator (the =) in C++.
(Note that the "become-like" operator doesn't exist in most OO languages like Java, C# or Python; = in object contexts there means reference assignment, which is like pointer assignment in C++;).
Summing up:
Casts Derived** -> Base** are forbidden, because they can cause a type error, because then you could end up with a pointer of type Derived* pointing to an object of type Base.
The problem you mentioned isn't a type error; it's a different type of error: mis-use of the interface of the derived object, rooting from the sorry fact that it has inherited the "become-like" operator of its parent class.
(Yes, I call op= in objects contexts "become-like" deliberately, as I feel that "assignment" isn't a good name to show what's happening here.)
Well the code you gave makes sense. Indeed the assignement operator cannot overrite data specific to Derived but only base. Virtual functions are still from Derived and not from Base.
*b = Base(3); // Ouch!
Here the object at *b really is a B, it's the base sub-object of *d. Only that base sub-object gets modified, the rest of the derived object isn't changed and d still points to the same object of the derived type.
You might not want to allow the base to be modified, but in terms if the type system it's correct. A Derived is a Base.
That's not true for the illegal pointer case. A Derived* is convertible to Base* but is not the same type. It violates the type system.
Allowing the conversion you're asking about would be no different to this:
Derived* d;
Base b;
d = &b;
d->x;
Reading through the good answers of my question I think I got the point of the issue, which comes from first principles in OO and has nothing to do with sub-objects and operator overloading.
The point is that you can use a Derived whenever a Base is required (substitution principle), but you cannot use a Derived* whenever a Base* is needed due to the possibility of assigning pointers of instances of derived classes to it.
Take a function with this prototype:
void f(Base **b)
f can do a bunch of things with b, dereferencing it among other things:
void f(Base **b)
{
Base *pb = *b;
...
}
If we passed to f a Derived**, it means that we are using a Derived* as a Base*, which is incorrect since we may assign a OtherDerived* to Base* but not to Derived*.
On the other way, take this function:
void f(Base *b)
If f dereferences b, then we would use a Derived in place of a Base, which is entirerly fine (provided that you give a correct implementation of your class hierarchies):
void f(Base *b)
{
Base pb = *b; // *b is a Derived? No problem!
}
To say it in another way: the substitution principles (use a derived class instead of the base one) works on instances, not on pointers, because the "concept" of a pointer to A is "points to an instance of whichever class inherits A", and the set of classes which inherits Base strictly contains the set of classes that inherits Derived.
I am having trouble with forcing data type changes has on my own objects. I have a base class say A and two classes derived from A called B and C. I pass objects B and C to a function that checks which type of object it is (B or C). Here is some example code below and the question to my problem:
enum ClassType {"B", "C"};
class A {
protected:
m_Type;
public:
ClassType Type() { return m_Type}
...
...
};
class B : public A {
otherMemberFunctions();
}
class C : public A {
otherMemberFunctions();
}
void WhatType(vector<A*>* candidates){
vector<B*> b_candidates(0);
vector<C*> c_candidates(0);
for(int i = 0; i < candidates->size(); i++){
if(candidates->at(i)->Type() == B ){
B* b = (B*) candidates->at(i);
b_candidates(b);
}
//Same idea for Object C
}
}
I would then use WhatType(vector<A*>* candidates) as follows
vector<B*>* b_example
WhatType((vector<A*>*) b_exmaple)
When I have filled the new vector b_candidates in the function WhatType. Will I still have access to the member functions in the B object or will I only have the access to the member functions in the base class A?
I am confused to what happens with the object when I change the type of the object.
Here
WhatType((vector<A*>*) b_exmaple)
and here
B* b = (B*) candidates->at(i);
When you receive a pointer to a polymorphic object you have two types: the "static" type of the object, which, in your case, will be A *, and its "dynamic" or "real" type, that depends on what was actually assigned to it.
Casting your A * to B * forces the compiler to consider that pointer as a pointer to B; this is safe as long as you actually know that that pointer is actually a pointer to B, otherwise the compiler will start writing nonsensical code (invoking B methods on data of another type).
The checks you are trying to implement are a homegrown version of RTTI, which is a mechanism that allows you to know which is the "real type" of a pointer or a reference to a polymorphic class, and to perform that kind of casts safely. Check out typeid and dynamic_cast on your C++ manual for more info about it. (Incidentally, IIRC dynamic_cast is not only for safety in case the dynamic type is wrong, but it may perform also some extra magic on your pointer if you use it in complicated class hierarchies; so, avoid C-style casting for polymorphic classes)
By the way, in general it's considered "code smell" to have to manually check the "real type" of the pointer in order to cast it and use its methods: the OOP ideal would be being able to do the work only though virtual methods available in the base class.
Big warning: RTTI works only on polymorphic classes, i.e. classes that have at least one virtual method. On the other hand, if you are building a class hierarchy where objects are being passed around as pointers to the base class you'll almost surely want to have a virtual destructor, so that's no big deal.
Since you cast to B*, you will have access to B's members.
The actual type of the objects does not change, of course, but if you only have a pointer (or reference) to the base class you can not access fields specific to the sub-classes.
What you can do to access sub-class fields is to use dynamic_cast to cast it to the sub-class:
A *a = new B; // We cant reach the members of class B in a
B *b = dynamic_cast<B *>(a); // But now we have a proper pointer to B
Ok, so if you had an object of type B instantiated on the heap and held by a pointer of type A. you can only see type A's member functions, to access type B's member functions you have to static_cast<B*> which is what the ... "(B*)" ... is doing.
dynamic cast is better as it will return a null if the conversion is not possible. but of course it happens a run-time so there's a penalty.
As B and C are À derived, a vector<B *> and vector<C *> contains A base class objects. If you ensure to set your A::m_Type attribute in your constructor, you will no have problems:
enum ClassType {'B', 'C'}; // see I modified your definition
class A {
protected:
ClassType m_Type;
public:
ClassType Type() { return m_Type};
...
...
};
class B : public A {
public:
B() : m_Type('B') {}
....
};
Using this, you will check without problems your B and Cobjects. After that, as you are casting base objects to derived ones, you will have fully access to their public methods and attributes.
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.
I had a question about C++ destructor behavior, more out of curiosity than anything else. I have the following classes:
Base.h
class BaseB;
class BaseA
{
public:
virtual int MethodA(BaseB *param1) = 0;
};
class BaseB
{
};
Imp.h
#include "Base.h"
#include <string>
class BImp;
class AImp : public BaseA
{
public:
AImp();
virtual ~AImp();
private:
AImp(const AImp&);
AImp& operator= (const AImp&);
public:
int MethodA(BaseB *param1) { return MethodA(reinterpret_cast<BImp *>(param1)); }
private:
int MethodA(BImp *param1);
};
class BImp : public BaseB
{
public:
BImp(std::string data1, std::string data2) : m_data1(data1), m_data2(data2) { }
~BImp();
std::string m_data1;
std::string m_data2;
private:
BImp();
BImp(const BImp&);
BImp& operator= (const BImp&);
};
Now, the issue is that with this code, everything works flawlessly. However, when I make the destructor for BImp virtual, on the call to AImp::MethodA, the class BImp seems to have its data (m_data1 and m_data2) uninitialized. I've checked and made sure the contained data is correct at construction time, so I was wondering what the reason behind this could be...
Cheers!
Edit: param1 was actually a reference to B in MethodA. Looks like I over-sanitized my real code a bit too much!
Edit2: Re-arranged the code a bit to show the two different files. Tested that this code compiles, a well. Sorry about that!
If you are casting between related types as you do in this case, you should use static_cast or dynamic_cast, rather than reinterpret_cast, because the compiler may adjust the object pointer value while casting it to a more derived type. The result of reinterpret_cast is undefined in this case, because it just takes the pointer value and pretends it's another object without any regard for object layout.
MethodA takes its parameters by value. This means a copy is passed (and the copy has to be destroyed). That's my best guess for why you might have a BImpl being destroyed that you didn't expect to be, but I don't see what the virtual or non-virtual nature of A's destructor could possibly have to do with it.
But this code can't compile - you use class B in declaring the virtual function in A, but B isn't defined until later. And I don't know what's going on with that cast - you can't reinterpret_cast class types. Perhaps if you work up a test case which demonstrates your issue, and post that?
There's a lot of iffy stuff in this code, so I'm amazed that it works or compiles in any case.
Passing parameters by value instead of reference to MethodA
Casting a B to a BImp via reinterpret_cast -- bad idea! If you're going to cast in that direction, dynamic_cast is the safest.
I fail to see how you're supposed to get a BImp out of a B. You are not invoking any constructors, and you have none that could be invoked that would accept a B. Your default constructor for BImp is private, and assigning a B that has no data, casted to a BImp that still has no data, to a BImp, still isn't going to give you any data!
Several comments:
Your base classes should have virtual destructors so the derived class' dtor is called instead of the just the base class dtor when the object is deleted.
MethodA taking a BaseB pointer as a parameter only to have the pointer reinterpreted as a BImp (a derived class of BaseB) is dangerous. There is no guarantee something else other than BImp is passed to MethodA. What would happen if just a BaseB object was to MethodA? Potentially lots of bad things, I would suspect.
I'm guessing your code "works flawlessly" because you only pass BImp to MethodA. If you are only passing BImp to MethodA then make the signature match the intent (this has the added benefit of removing that awful reinterpret call).
Your code is ill-formed. It is not valid C++. In C++ language reinterpret_cast can only be used to cast between pointer types, reference types, to perform pointer-to-integer conversions (in either direction).
In your code you are trying to use reinterpret_cast to convert from type B to type BImp. This is explicitly illegal in C++. If your compiler allows this code, you have to consult your compiler's documentation in order to determine what's going on.
Other replies already mentioned "slicing". Keep in mind that this is nothing more than just a guess about specific non-standard behavior of your specific compiler. It has nothing to do with C++ language.