Dart typecasting error - casting

I have an abstract class Event and a concrete subclass that extends it called PlaceChangeEvent. Inside an event listener, I have the following code:
void onEvent(Event event) {
PlaceChangeEvent pce = null;
if(event is PlaceChangeEvent)
pce = (PlaceChangeEvent)event; // <== error is here
else
throw new Exception("Event is not a PlaceChangeEvent.");
Place place = pce.place;
presenterProvider.display(place);
}
So if the runtime type of event is PlaceChangeEvent, then I need to cast the event to that type so that I can access its properties. But I'm getting a compiler error on the typecast, stating:
A value of type 'Type' cannot be assigned to a variable of type 'PlaceChangeEvent'
Where am I going wrong, and what do I need to do to fix it?

In Dart
upcasts are implicit. If B is a subclass of A, then B b = a (where a is an instance of class A) is warning free and silently casts a to B. In Java you would have needed to write B b = (B) a.
the dynamic type is an always-present escape hatch. If B and C are not in the same hierarchy, then temporarily assigning to the dynamic type will make the cast warning-free.
B b = someB;
var tmp = b;
C c = tmp;
One can do an explicit check using is. The is check returns true if the object is of the right type. There are also some very simple rules that propagate is-check types. For example, if is is used inside an if condition, then the corresponding branch uses this information for type-warnings.
Object o;
o.foo(); // warning: foo does not exist on Object.
if (o is A) { // assuming that A contains 'foo'.
o.foo(); // warning-free.
}
One can explicitly check and throw if a type is not the expected one with as. This operator does not throw when the left-hand side is null.
For your example this boils down to:
No explicit check (1):
void onEvent(Event event) {
// Implicit upcast. PlaceChangeEvent is subclass of Event.
PlaceChangeEvent pce = event;
Place place = pce.place;
presenterProvider.display(place);
}
With an is-check (3):
void onEvent(Event event) {
if (event is PlaceChangeEvent) {
// Static type system propagates type. No need for variable.
Place place = event.place;
presenterProvider.display(place);
} else {
// Note: this doesn't look like an exception, but an error.
throw new Exception("Event is not a PlaceChangeEvent.");
}
}
Using as (4):
void onEvent(Event event) {
Place place = (event as PlaceChangeEvent).place;
presenterProvider.display(place);
}
Alternatively, if you expect to receive a PlaceChangeEvent, you should simply change the type of the argument:
void onEvent(PlaceChangeEvent event) {
Place place = event.place;
presenterProvider.display(place);
}
In checked mode this will catch bad types, and in unchecked mode it will throw when accessing event.place. This is generally the preferred way.

Try this:
pce = event as PlaceChangeEvent;

Related

cannot declare variable ‘pdu’ to be of abstract type ‘Tins::PDU’

I'm using libtins to capture packets and moodycamel Concurrent Queue to queue captured packets.
I note that the dequeue operation fails because PDU is an abstract type.
Hence it fails to compile,
error: cannot declare variable ‘pdu’ to be of abstract type ‘Tins::PDU’
I am not sure what to do at this stage to fix this error.
I've attempted the pointer route but it didn't compile too
Tins::PDU *pdu;
if(PacketQueue.try_dequeue(pdu) == false) {
continue;
}
The error,
error: cannot convert ‘std::remove_reference<Tins::PDU&>::type {aka Tins::PDU}’ to ‘Tins::PDU*’ in assignment
element = std::move(el); // NOLINT
~~~~~~~~^~~~~~~~~~~~~~~
Code
moodycamel::ConcurrentQueue<PDU> PacketQueue;
void worker()
{
while(true) {
Tins::PDU pdu;
if(PacketQueue.try_dequeue(pdu) == false) {
continue;
}
// Do Work
}
}
bool callback(PDU &pdu)
{
PacketQueue.enqueue(pdu);
return true;
}
moodycamel::ConcurrentQueue<PDU> PacketQueue;
...
bool callback(PDU &pdu)
{
PacketQueue.enqueue(pdu);
This cannot work correctly.
You received a reference to the base class of some concrete object.
Enqueueing this by value causes object slicing - you're just copying the base-class subobject and discarding all the derived class state (and type information).
The fact that the compiler stopped you from dequeuing this abstract type is a handy coincidence, because otherwise you would have had to figure out why your successful enqueue/dequeue was producing garbage pdus.
I've attempted the pointer route ...
Well, you need some kind of indirection. You haven't shown the code you tried, but I think you forgot to change the type of the queue to match.
If you want to en/de-queue pointers, you need to:
change your queue to be a queue of pointers
clone (polymorphic deep-copy) the object to be enqueued (assuming the object whose reference you get, will be cleaned up after the callback returns)
remember you're now responsible for destroying the cloned pdu after you dequeue it (or, better, just use unique_ptr in the first place)
The correct solution probably looks like this (completely untested) example:
// title case is conventionally used for types, not variables
// (of course, it would also be better to avoid globals ...)
moodycamel::ConcurrentQueue<std::unique_ptr<PDU>> packetQueue;
void worker()
{
while(true) {
std::unique_ptr<PDU> pdu;
if(packetQueue.try_dequeue(pdu) == false) {
continue;
}
// Do Work on *pdu
}
}
bool callback(PDU &pdu)
{
packetQueue.enqueue(std::unique_ptr<Tins::PDU>(pdu.clone()));
return true;
}

D opEquals() and opCast() give me a Segmentation Fault

I am trying to write a library of types representing a Global Trade Identification Number (GTIN) in the D Programming Language. There are four kinds of GTIN's, each named after the length of the number itself: GTIN8, GTIN12, GTIN13, and GTIN14. Each one of these is modeled as a class inheriting from an abstract GTIN class.
In the abstract GTIN class, I am overriding the opEquals operator to compare two GTINs of any kind. Since all of the smaller GTINs can be mapped to a broader GTIN14, each GTIN in the comparison gets cast to a GTIN14 first, then compared.
This all works fine until I compare one or more GTIN13s (or presumably, a smaller GTIN type as well), in which case, I get a segmentation fault.
It all begins with this unit test:
GTIN13 gtin1 = new GTIN13("123456789012");
GTIN13 gtin2 = new GTIN13("123456789012");
assert(gtin1 == gtin2);
The operator opEquals() has a signature of Object.opEquals(Object o), and changing the signature to anything else does not override ==. In my case, this becomes a call to gtin1.opEquals(cast(Object) gtin2). My opEquals override looks like this (subtracting the accumulated commented-out code and debug statements):
public override #trusted
bool opEquals(Object other)
{
GTIN14 a = cast(GTIN14) this;
GTIN14 b = cast(GTIN14) other;
for (int i; i < a.digits.length; i++)
{
if (a.digits[i] != b.digits[i]) return false;
}
return true;
}
As you can see, each GTIN is cast to a GTIN14 at the start of the function; however, other is first cast to an Object.
public
GTIN14 opCast(GTIN14)()
{
string currentGTINString = this.toString()[0 .. $-1];
while (currentGTINString.length < 13)
currentGTINString = ('0' ~ currentGTINString);
return new GTIN14(currentGTINString);
}
Further, my friend writeln() tells me that after the line GTIN14 b = cast(GTIN14) other; is executed, b is null. (It is not null before that line.)
So, in summary, the problem seems to be that casting a GTIN of any kind other than GTIN14 to an Object, then back to GTIN14 somehow deletes the object altogether. Is this a bug? Is this a problem with my code? Is there a workaround that does not compromise code quality?
I will appreciate any help I can get.
All right, I have several comments from your pastebin.
public abstract
class GlobalTradeItemNumber
{
// this could prolly just return _digits.length too.
public abstract #property
size_t length();
My general comment here is your code could be a bit simplified by making the length be borrowed from the array.... or you could also do something like a templated class with the length as a parameter.
I'll come back to that later though, first, let's fix your code. Moving on in the class:
public
/*
Note #1:
OK, this line is wrong:
//GTIN14 opCast(GTIN14)()
It should probably be:
*/
GTIN14 opCast(T : GTIN14)()
{
string currentGTINString = this.toString()[0 .. $-1];
while (currentGTINString.length < 13)
currentGTINString = ('0' ~ currentGTINString);
return new GTIN14(currentGTINString);
}
// we also need one for converting to the other sizes
// this could also be done with metaprogramming
GTIN13 opCast(T : GTIN13)()
{
string currentGTINString = this.toString()[0 .. $-1];
while (currentGTINString.length < 12)
currentGTINString = ('0' ~ currentGTINString);
return new GTIN13(currentGTINString);
}
The reason that line is wrong is that it actually defines a local template argument called GTIN14 which could be anything, and shadows the outer name!
So, my change here makes a new name T, which is then specialized to only match on the GTIN14 name from outside. See: http://dlang.org/spec/template.html#parameters_specialization
But then, it only applies to GTIN14, so I also added a second function that goes GTIN13 too.
If you were using a templated class, the specialization could also extract the length and you'd have one function that does them all. Or, if length as a compile-time constant (an enum) in each child class, you could pull it from there too.
Regardless, fixing your current code can be done with just the specialization syntax (T : class_name) and adding functions for the other subclasses too.
public
ulong toNumber()
{
ulong result;
// a note here: I would probably just have
// int exponent = 1;
// then exponent *= 10; in each loop instead of pow each time.
for (size_t i = this.length-1; i > 0; i--)
{
result += (this._digits[i] * (10^^(this._digits.length-i)));
}
return result;
}
Well, not much to say there, your code works, I would just write it a bit differently. The accumulator variable pattern would optimize it a wee bit. Of course, not really important here, just something to keep in mind.
/*
Note #2: this is where things get broken
*/
public override #trusted
bool opEquals(Object other)
{
/*
these are actually two different kinds of casts
GTIN14 b = cast(GTIN14) other; // does a generic dynamic cast!
GTIN14 a = cast(GTIN14) this; // actually calls the opCast
*/
GTIN obj = cast(GTIN) other;
if(obj is null) // which might return null because Object is not necessarily an instance of your class
return false; // definitely not a match
GTIN14 b = cast(GTIN14) obj;
GTIN14 a = cast(GTIN14) this;
for (int i; i < a.digits.length; i++)
{
if (a.digits[i] != b.digits[i]) return false;
}
return true;
}
public override #trusted
int opCmp(Object other)
{
// GTIN14 that = cast(GTIN14) other; // a generic dynamic cast!
GTIN obj = cast(GTIN) other;
if(obj is null) // which might return null because Object is not necessarily an instance of your class
return -1; // so return something indicating not a match
GTIN14 that = cast(GTIN14) obj; // now you can use your custom cast
const ulong thisNumber = this.toNumber();
const ulong thatNumber = that.toNumber();
if (thisNumber == thatNumber) return 0;
return ((thisNumber / 10u) > (thatNumber / 10u) ? 1 : -1);
}
The other opCmps in the child classes make the same mistake and can be fixed the same way.
But this is the main thing causing your trouble - the same cast syntax actually does two different things!
See, the static type of other is the generic base class Object, so it isn't aware of your custom cast function yet. (opCast, being a template, cannot be virtual and thus is not override like other functions that modify the behavior of generic function)
Instead, it does a generic dynamic_cast (that's the C++ name, D just calls them all cast, but it is the same concept so you can read more about it by searching for the C++ term if you like). It tries to convert the base class/interface back to the subclass using a runtime type tag. If it is indeed an instance of that class (or one of its own subclasses), the cast succeeds and you get the reference. Otherwise, it returns null. This is the cause of your segfault.
On the other hand, the cast(xxx) this already knows it is an instance of GTIN (or one of its subclasses), so it is able to use your custom opCast conversion. So, your a variable called the right function and got populated correctly, but your b variable would be null... unless you happened to actually be comparing two GTIN14 instances. Then the dynamic cast would succeed, but not for the other classes.
So, the fix is to first cast that generic Object other back to your GTIN base class, check for null (this would happen if a user wrote like GTIN14 a = new GTIN14("xxx"); Object b = new Object(); assert(a == b); /* uh oh, b is an Object, so it should just return null */.
BTW, when comparing against null, you should usually use a is null instead of a == b because if a itself is null, it will crash when trying to access the virtual opEquals function!
Anyway, after you cast it back to GTIN, then you can cast again and invoke your conversion function.
Alternatively, you might also use a different named function like perhaps toGTIN14 in the base class that generically does the conversion, and you just call that from each instance of the base class and convert them that way instead of using the cast keyword. That'd actually be the way I'd write it - it is my preference, but both ways work.
Both opEquals and opCmp, from any classes where they are implemented, need to follow this same pattern. In opEquals you can see I return false when it is null, since they obviously aren't equal if they can't even be converted to a common type!
But in opCmp, you don't want to return 0 since that means equal, but what to actually return is a mystery to me.... I just did -1 so all the other objects in that array would be sorted earlier but maybe you have a better idea. I don't know what's best.
Anyway yeah, doing those changes should fix your code.
Lastly, as a bonus, here's an implementation of the generic templated class:
alias GTIN14 = GlobalTradeItemNumberImpl!14;
alias GTIN13 = GlobalTradeItemNumberImpl!13;
public
class GlobalTradeItemNumberImpl(int size) : GlobalTradeItemNumber
{
public override #property
size_t length()
{
return size;
}
this(string digits)
{
super(digits);
}
}
If you've ever looked at some of Phobos' innards, you will see patterns similar to this in std.base64 and std.digest.
With that, all the functionality is actually in the base class now. You can rewrite the opCast as thus in the base class:
T opCast(T : GlobalTradeItemNumberImpl!N, int N)()
{
string currentGTINString = this.toString()[0 .. $-1];
while (currentGTINString.length < (N-1))
currentGTINString = ('0' ~ currentGTINString);
return new T(currentGTINString);
}
The specialization there uses the "pattern matching" described in form #7 of this: http://dlang.org/spec/expression.html#IsExpression to catch any random N, and extract what it is for use inside the function.
There's other optimizations we could do too if you're interested, like the use of the ~ operator, or it could even be changed from classes to struct using alias this to combine common functionality.. but I'll let you play with that if you want to :)

Function Return Type: Pointer, Reference or something else?

Let us assume I always need the direkt return type of the function to be of a errorcode (success of calculation or failure) , then I will return some arguments as parameters. Is it better to define them as reference (and create them before empty) or better to return pointer?
Edit: I should be more precise: The errorcode is obligatory because I have to stick to the coding guidline given.
Possibility A:
ErrorCode func( some_parameters ... , ReturnType & result)
...
ReturnType result; // empty constructor, probably not good practice
func( some_parameters ..., result)
Possibility B:
ErrorCode func( some_parameters ... , ReturnType * result){
...
result = new ReturnType(...)
...
}
...
ReturnType * result; // void pointer
func( some_parameters ..., result)
...
delete result; // this is needed if I do not use a smart pointer
Even better: Maybe you have a more appropriate solution?
Edit: Please indicate which standard you are using, since unfortunatelly (guidelines) I have to stick to C++98.
I would do the following (and in general do)
1.) throw an exception instead of returning error codes
if this is not possible (for any reason)
2.) return the pointer directly (either raw or std::unique_ptr) and return nullptr for failure
if return type has to be bool or not all objects returned are (pointers / heap allocated)
3.) return your error code (bool or enum class) and accept a reference parameter for all objects that are to be initialized (must have objects so to speak) and pointers to objects that may be optionally created / initialized
if the object cannot be created in advance to the call (e.g. because it is not default constructible)
4.) pass a reference to a pointer (raw or std::unique_ptr) or a pointer to a pointer, which will then be filled by the function
std::optional (or similar) may be an option if you only have a true/false return code.
I don't like returning std::pair or std::tuple because it can make your code look quite annoying if you have to start using .first/.second or std::get<>() to access your different return types. Using std::tie() can reduce this a little bit, but it is not (yet) very comfortable to use and prevents the use of const.
Examples:
std::unique_ptr<MyClass> func1() { /* ... */ throw MyException("..."); }
std::unique_ptr<MyClass> func2() { /* ... */ }
ErrorCode func3(MyClass& obj, std::string* info = nullptr) { /* ... */ }
ErrorCode func4(std::unique_ptr<MyClass>& obj) { /* ... */ }
int main()
{
try
{
auto myObj1 = func1();
// use ...
}
catch(const MyException& e)
{
// handle error ...
}
if(auto myObj2 = func2())
{
// use ...
}
MyClass myObj3;
std::string info;
ErrorCode error = func3(myObj3, &info);
if(error == ErrorCode::NoError)
{
// use ...
}
std::unique_ptr<MyClass> myObj4;
ErrorCode error = func4(myObj4);
if(error == ErrorCode::NoError)
{
// use ...
}
}
Edit: And in general it is advisable to keep your API consistent, so if you already have a medium or large codebase, which makes use of one or the other strategy you should stick to that (if you do not have good reasons not to).
This is a typical example for std::optional. Sadly it isn't available yet, so you want to use boost::optional.
This is assuming that the result is always either "success with result" or "fail without result". If your result code is more complicated you can return
std::pair<ResultCode, std::optional<ReturnType>>.
It would be good style to to use the return value for all return information. For example:
std::tuple<bool, ReturnType> func(input_args....)
Alternatively, the return type could be std::optional (or its precursor) if the status code is boolean, with an empty optional indicating that the function failed.
However, if the calculation is supposed to normally succeed, and only fail in rare circumstances, it would be better style to just return ReturnType, and throw an exception to indicate failure.
Code is much easier to read when it doesn't have error-checking on every single return value; but to be robust code those errors do need to be checked somewhere or other. Exceptions let you handle a range of exceptional conditions in a single place.
Don't know if it's applicable in your situation but if you have only two state return type then maybe just return pointer from your function and then test if it is nullptr?

Have I to throw an exception?

Suppose I have a static method of my class that returns an object of the same type of my class. To create the object for example this method have to parse a string:
class C
{
public:
static C get_obj(const std::string& str)
{
C obj;
// Parse the string and set obj properties
return obj;
}
};
If, when I parse the string, I get an error and the object can't be constructed as a valid object, have I to throw an exception or what else?
Given that there is a possibility of failure in get_obj the failure must be reported back to the caller in some manner. This is typically either done by
Throwing an exception
Communicating the failure in the output of the method
In this particular case the only output of the method is a C instance. Given that throwing an exception is probably the best option for a method of this signature. The only other choice is to embed the success / failure inside the C object which you almost certainly don't want to do.
Another way to approach this problem is the try_parse pattern. Let a bool return indicate success / failure and return the constructed object on success through a reference parameter
bool try_parse(const std::string& str, C& obj) {
if (string is valid) {
obj = C(...);
return true;
}
return false;
}
I'd say you should throw an exception. This way you notify the client that the obj could not be obtained, and force him to deal with this.
If not important (not critical), you could return a special C that would act as a sentinel value indicating that something went wrong. The client will choose whether to do something about it or not.
I'd go with the exception. The second approach is not recommended.
Yes it is perfectly valid to throw an exception.
Its the same reason when constructing an object, if you cannot proceed with the construction of an object you have very little choice but to throw an exception.
Yes, you do need to throw an exception.
class C
{
public:
static C get_obj(const std::string& str)
{
try
{
C obj;
// Parse the string and set obj properties
return obj;
}
catch (int x)
{
cout "blahblah";
}
}
};
If the object cannot be constructed you risk a 0 variable, which can cause a lot of trouble further on

Declaring different data types inside if statements depending on circumstance: how to shut up the compiler?

Hey so I'm making a serialization function that takes a base class pointer 'Joint', extracts the 'type' of joint descendent it is, and then want to instantiate the correct type of 'definition' based on whatever kind of 'joint' the pointer is really pointing too.
However i'm still getting errors about the base class joint not
containing functions that a descendent class does have, even though i
static_cast the pointer to the correct type. How do i make the
complier realize the pointer is being casted too a new type that does
have the function?
I also am getting errors about the 'typedef', which can be different
based on what 'type' the joint* is, with the compile saying it's
undefined. How do i tell the compiler that no matter what, one of the if statements will be true? (Jointdef is declared inside the if
statements)
Here's the source:
template<class Archive>
b2Joint* const preSave(Archive & ar, b2Joint* Joint)
{
int Type = Joint->GetType();
ar & Type; // pulled out first so we know what kind of JointDef to instantiate
if(Type == b2JointType::e_distanceJoint){
b2DistanceJointDef JointDef;
static_cast<b2DistanceJoint *>(Joint);
JointDef.localAnchorA= Joint->GetAnchorA();
JointDef.localAnchorB= Joint->GetAnchorB();
JointDef.length= Joint->GetLength();
JointDef.frequencyHz= Joint->GetFrequency();
}
if(Type == b2JointType::e_weldJoint){
b2WeldJointDef JointDef;
static_cast<b2WeldJoint *>(Joint);
JointDef.localAnchorA= Joint->GetAnchorA();
JointDef.localAnchorB= Joint->GetAnchorB();
JointDef.referenceAngle= Joint->GetReferenceAngle(); // function added
}
if(Type == b2JointType::e_gearJoint){ //TODO / NOTE: this must be loaded last since to be linked joints must first be made
b2GearJointDef JointDef; // unless joints are in order of when they were created.......
static_cast<b2GearJoint *>(Joint);
JointDef.joint1= Joint->GetJoint1; //function added
JointDef.joint2= Joint->GetJoint2; //function added
JointDef.ratio= Joint->GetRatio();
}
if(Type == b2JointType::e_lineJoint){
b2LineJointDef JointDef;
static_cast<b2LineJoint *>(Joint);
JointDef.localAnchorA= Joint->GetAnchorA();
JointDef.localAnchorB= Joint->GetAnchorB();
JointDef.enableLimit; Joint->IsLimitEnabled();
JointDef.localAxisA= Joint->GetLocalAxisA() //function made
JointDef.lowerTranslation= Joint->GetLowerLimit();
JointDef.upperTranslation= Joint->GetUpperLimit();
JointDef.enableMotor= Joint->IsMotorEnabled();
JointDef.maxMotorForce= Joint->GetMaxMotorForce();
JointDef.motorSpeed= Joint->GetMotorSpeed();
}
if(Type == b2JointType::e_mouseJoint){
b2MouseJointDef JointDef;
static_cast<b2MouseJoint *>(Joint);
JointDef.target= Joint->GetTarget();
JointDef.maxForce= Joint->GetMaxForce();
JointDef.frequencyHz= Joint->GetFrequency();
JointDef.dampingRatio= Joint->GetDampingRatio();
}
if(Type == b2JointType::e_prismaticJoint){
b2PrismaticJointDef JointDef;
static_cast<b2PrismaticJoint *>(Joint);
JointDef.localAnchorA= Joint->GetAnchorA();
JointDef.localAnchorB= Joint->GetAnchorB();
JointDef.enableLimit; Joint->IsLimitEnabled();
JointDef.referenceAngle= Joint->GetReferenceAngle(); //added function
JointDef.localAxis1= Joint->GetLocalAxis1(); //added function
JointDef.maxMotorForce= Joint->GetMaxMotorForce(); //added function
JointDef.lowerTranslation= Joint->GetLowerLimit();
JointDef.upperTranslation= Joint->GetUpperLimit();
JointDef.enableMotor= Joint->IsMotorEnabled();
JointDef.motorSpeed= Joint->GetMotorSpeed();
}
if(Type == b2JointType::e_pulleyJoint){
b2PulleyJointDef JointDef;
static_cast<b2PulleyJoint *>(Joint);
JointDef.localAnchorA= Joint->GetAnchorA();
JointDef.localAnchorB= Joint->GetAnchorB();
JointDef.groundAnchorA= Joint->GetGroundAnchorA();
JointDef.groundAnchorB= Joint->GetGroundAnchorB();
JointDef.lengthA= Joint->GetLength1();
JointDef.lengthB= Joint->GetLength2();
JointDef.maxLengthA= Joint->GetMaxPulleyLengthA(); //added function
JointDef.maxLengthB= Joint->GetMaxPulleyLengthB(); //added function
JointDef.ratio= Joint->GetRatio();
}
if(Type == b2JointType::e_revoluteJoint){
b2RevoluteJointDef JointDef;
static_cast<b2RevoluteJoint *>(Joint);
JointDef.localAnchorA= Joint->GetAnchorA();
JointDef.localAnchorB= Joint->GetAnchorB();
JointDef.enableLimit; Joint->IsLimitEnabled();
JointDef.enableMotor= Joint->IsMotorEnabled();
JointDef.motorSpeed= Joint->GetMotorSpeed();
JointDef.maxMotorTorque= Joint->GetMaxMotorTorque() //added function
JointDef.referenceAngle Joint->GetReferenceAngle() //added function
JointDef.lowerAngle= Joint->GetLowerLimit();
JointDef.upperAngle= Joint->GetUpperLimit();
}
else{ b2JointDef
//if(Type == b2JointType::e_frictionJoint){ QUESTION: what is this... not in box2d guide...
// base class JointDef data:
JointDef.type= Joint->GetType();
JointDef.userData= Joint->GetUserData();
JointDef.bodyA= Joint->GetBodyA();
JointDef.bodyB= Joint->GetBodyB();
JointDef.collideConnected= Joint->IsCollideConnected(); //added function
ar & JointDef;
return Joint;
}
Your use of static_cast is the problem. static_cast does not redefine the type of a variable: instead, it returns the value casted into the type you've asked for.
Type* variable = static_cast<Type*>(variableToCast);
Also, if your classes make use of polymorphism, consider using dynamic_cast instead, which makes use of the (not very powerful) run-time type information system of C++.
if (b2DistanceJointDef* def = dynamic_cast<b2JointTypeDef*>(Joint))
{
// if you reach this block, this means Joint is actually a pointer to
// a b2JointTypeDef object; and you may use the `def` variable to access
// its members
}
Better yet, if you're into that kind of thing, and if it makes sense in your design, you might consider a polymorphic method to eliminate this type switch. There is broad discussion about why it's better on this site and almost everywhere to avoid explicit type switches.
For the typedef statement, you have to make the distinction between compile-time information and runtime information. C++ is a statically typed language: this means it needs to know everything about the type of a variable during the compilation stage. A type definition cannot vary based on a runtime condition: it needs to be resolved during the compilation stage.
Besides, symbols (basically, anything that has an identifier is a symbol) cannot be used outside their scope. So if you declare anything under an if block, you won't be able to access it from outside that if block.
Since typedefs make symbols using a typedef inside a scope makes the defined type available until the end of the scope, and no further. For instance:
if (foo)
{
typedef int myInt;
myInt var = 4; // works
}
myInt baz = 4; // fails