Why won't this cast?

M

mark

class SORef {...};
class SelectedFORef : public SORef {...};


SOFORef SOCastToSOF(SORef sor) {
SelectedFORef sof=nil;
sof=dynamic_cast<SelectedFORef>(sor);
return sof;
};

I am getting a problem where sor is not being cast to sof (becomes nil)
even though sor IS a SelectedFORef underneath. (I have a debug method
with details contents and type).

I am not a C++ expert.
What am I doing wrong?

Mark
 
I

Ian Collins

mark said:
nil == NULL.
Pascal version of NULL.

Then why hide it? You can't assign NULL to a class object, only a pointer.

You can't apply a dynamic_cast to a class object, only a reference of a
pointer to one.
 
M

mark

Ian Collins said:
Then why hide it? You can't assign NULL to a class object, only a pointer.

You can't apply a dynamic_cast to a class object, only a reference of a
pointer to one.

I am idiot.
Sorry.
Should be:

class SOObject {...};
typdef class SOObject * SORef;

class SelectedFileObject : public SOObject {...};
typedef class SelectedFileObject * SelectedFORef;

SOFORef SOCastToSOF(SORef sor) {
SelectedFORef sof=nil;
sof=dynamic_cast<SelectedFORef>(sor);
return sof;
};
 
I

Ian Collins

mark said:
I am idiot.
Sorry.
Should be:

class SOObject {...};
typdef class SOObject * SORef;

class SelectedFileObject : public SOObject {...};
typedef class SelectedFileObject * SelectedFORef;
It's seldom, if ever, a good idea to hide pointer types behind typedefs.
SOFORef SOCastToSOF(SORef sor) {
SelectedFORef sof=nil;
sof=dynamic_cast<SelectedFORef>(sor);
return sof;
};

Why not

SelectedFORef sof = dynamic_cast<SelectedFORef>(sor);
 
M

mark

Ian Collins said:
It's seldom, if ever, a good idea to hide pointer types behind typedefs.

Have to. The class pointer is available to plugins. And C++ doesn't like
plugins. So I typedef as a struct * for plugins and use accessor
routines.
This is an accessor routine for plugins.
The debugger shows it to still be a SelectedFORef class instance.
Why not

SelectedFORef sof = dynamic_cast<SelectedFORef>(sor);

Did try that. Makes no difference.
Would the typedef actually screw things up?
 
J

John Harrison

mark said:
Have to. The class pointer is available to plugins. And C++ doesn't like
plugins. So I typedef as a struct * for plugins and use accessor
routines.

That's not a reason that makes any sense to me, (not saying it is wrong
though).
This is an accessor routine for plugins.
The debugger shows it to still be a SelectedFORef class instance.


Did try that. Makes no difference.
Would the typedef actually screw things up?

No.

Does class SOObject have at least one virtual function? You need at
least one virtual function for dynamic_cast to work.

When you say the cast is not working, what *exactly* do you mean? How
can you tell the cast is not working?

john
 
M

mark

John Harrison said:
That's not a reason that makes any sense to me, (not saying it is wrong
though).


No.

Does class SOObject have at least one virtual function? You need at
least one virtual function for dynamic_cast to work.

When you say the cast is not working, what *exactly* do you mean? How
can you tell the cast is not working?
Mac OS X gdb debugger.
Inspecting sor with XCode/gdb shows it to be a SelectedFileObject
underneath. It's type is listed as such and not the base class SORef.
So the dynamic_cast should work (according to the C++ book I have,
virtual

Here's the full class definitions.

class SelectedObject {
UInt16 refCt;

SelObjectClass objectClass;
OSType ready;
protected:
SOOwnerID ID; // need to identify where the SO belongs. An SO in one
view will have
// different select flags to an SO in another view
SelObjectType objectType; // NYI
SelectionFlag selections;

static CFMutableSetRef soCache;
static void SOCacheSetProc(const void* value, void* ctx);
friend SORef CheckSOCache(SelObjectClass objClass, UInt16 objType,
SOOwnerID iID, void* data);
virtual OSStatus CheckCache(SelObjectClass objClass, UInt16 dataType,
void* data,
SORef *sor);


// the arrays are used to send one select/deselect event when a whole
lot
// of objects are selected/deselected. Sending 1000+ deselected
events is not a good
// idea
static CritRgn recentSelRgn;
static CFMutableSetRef recentlySelected;
static CFMutableSetRef recentlyDeselected;
static OSStatus PostMassSelOfOwner(SOOwnerID ID, Boolean selOrDesel,
CFArrayRef itsItems);
static OSStatus PostMassSelectEvents(SOOwnerID whichID=0); // clears
both arrays after sending
// dtEventKindObjectsSelected & dtEventKindObjectsSelected
// If zero is passed, all are sent (in seperate events for each ID)
OSStatus AddToSelected();
OSStatus AddToDeselected();

void SOCleanup();
public:
SelectedObject(SelObjectClass theObjClass, SOOwnerID ID);
SelectedObject(const SelectedObject &obj);
virtual ~SelectedObject();
UInt16 Retain();
UInt16 Release();
SelObjectClass GetObjectClass();
virtual SelObjectType GetObjectType(); // NYI. Will always return
zero.
SOOwnerID GetOwnerID();

virtual CFStringRef CopySOString();

virtual UInt64 GetSOData64(); // these two will always return zero
for the base class
virtual UInt32 GetSOData32(); // it is up to the subclasses to return
the correct values

SelectionFlag GetSelectFlags();
void DefineSelectFlag(SelectionFlag theFlags, Boolean newValue);
void ToggleSelectFlag(SelectionFlag theFlags);
Boolean IsSelectedOr(SelectionFlag whichFlags); // returns true if
any of the passed flags are set
Boolean IsSelectedAnd(SelectionFlag whichFlags); // returns true if
all of the passed flags are set
Boolean AnySelection(); // returns true is any flag is set

void PostSelectedEvent(Boolean selected);

virtual Boolean operator==(SelectedObject &obj);

virtual void DebugPrint(UInt32 v=0); // printf
virtual CFStringRef DebugString(UInt32 v=0); // CFStringRef -> CFShow
};

//-----------------------------------------------------------------------
--------------

class SelectedFileObject:public SelectedObject {
OSType sfoReady;
protected:
FSRef fsr;

virtual OSStatus CheckCache(SelObjectClass objClass, UInt16 dataType,
void* data,
SORef *sor);
void SFOCleanup();
public:
SelectedFileObject(const FSRef* fsrptr, SOOwnerID ID);
SelectedFileObject(const char* cpath, SOOwnerID ID);
SelectedFileObject(CFURLRef url, SOOwnerID ID);
SelectedFileObject(const SelectedFileObject &obj);
~SelectedFileObject();

CFStringRef CopySOString();
UInt64 GetSOData64();
UInt32 GetSOData32();
FSRef* GetFSRefPtr();
virtual CFStringRef CopyName();

Boolean operator==(SelectedFileObject &obj);

void DebugPrint(UInt32 v=0); // printf
CFStringRef DebugString(UInt32 v=0); // CFStringRef -> CFShow
};

typedef class SelectedFileObject* SelectedFORef;
typedef SelectedFORef SOFORef;
 
J

John Harrison

mark said:
Mac OS X gdb debugger.
Inspecting sor with XCode/gdb shows it to be a SelectedFileObject
underneath. It's type is listed as such and not the base class SORef.
So the dynamic_cast should work (according to the C++ book I have,

Right, so before you do the cast you definitely have a
SelectedFileObject, but if was after that I was wondering about. Does
NULL get assigned to sof, or something else? I'm asking how you know it
failed, not why you expect it to work. Just trying to eliminate all the
possibilities.

john
 
J

John Harrison

I am idiot.
[snip]


Here's the full class definitions.

class SelectedObject {
UInt16 refCt;

[snip]


//-----------------------------------------------------------------------
--------------

class SelectedFileObject:public SelectedObject {
OSType sfoReady;
protected:
[snip]


typedef class SelectedFileObject* SelectedFORef;
typedef SelectedFORef SOFORef;

There's some confusion here

In your original code, the base class is called SOObject, in the class
definitions posted more recently, it's SelectedObject.

Could this be the problem, are you getting mixed up with your names?

john
 
M

mark

John Harrison said:
Right, so before you do the cast you definitely have a
SelectedFileObject, but if was after that I was wondering about. Does
NULL get assigned to sof, or something else? I'm asking how you know it
failed, not why you expect it to work. Just trying to eliminate all the
possibilities.

john

SelectedFORef sof=nil; <-- habit of setting vars to defaults.

sof=dynamic_cast<SelectedFORef>(sor); <-- sof is set to nil/NULL by
dynamic_cast

This routine is invoked by a plugin. sor is passed from APP -> PLUGIN
-> APP (above routine). The plugin just has a pointer to work with.
 
M

mark

I am idiot.
Sorry.
Should be:

class SOObject {...};
typdef class SOObject * SORef;

class SelectedFileObject : public SOObject {...};
typedef class SelectedFileObject * SelectedFORef;
[snip]


Here's the full class definitions.

class SelectedObject {
UInt16 refCt;

[snip]


//-----------------------------------------------------------------------
--------------

class SelectedFileObject:public SelectedObject {
OSType sfoReady;
protected:
[snip]


typedef class SelectedFileObject* SelectedFORef;
typedef SelectedFORef SOFORef;

There's some confusion here

In your original code, the base class is called SOObject, in the class
definitions posted more recently, it's SelectedObject.

Could this be the problem, are you getting mixed up with your names?

john[/QUOTE]

No.
The original posts were off the top of my head. Couldn't remember the
spellings.
I am not having a very intelligent day today.
The actual routine is this:

SOFORef SOCastToSOF(SORef sor) {
SelectedFORef sof=nil;
sof=dynamic_cast<SelectedFORef>(sor);
return sof;
};

Classes as given in previous post.

I changed the above to this:

OFORef SOCastToSOF(SORef sor) {
if (sor==nil) {return nil;}
SelectedFORef sof=nil;
printf("%s\n", typeid(*sor).name());
printf("%s\n", typeid(SelectedFileObject).name());
if (typeid(*sor)==typeid(SelectedFileObject)) {
sof=(SOFORef)sor;
}
else {sof=nil;}
// sof=dynamic_cast<SelectedFORef>(sor);
return sof;
};

The typeid.name() for '*sor' & 'SelectedFileObject' returned
'18SelectedFileObject'.
But the typeid(*sor)==typeid(SelectedFileObject) evaluates to false.
 
I

Ian Collins

mark said:
SelectedFORef sof=nil; <-- habit of setting vars to defaults.
Pointless when it gets assigned on the next line...
sof=dynamic_cast<SelectedFORef>(sor); <-- sof is set to nil/NULL by
dynamic_cast

This routine is invoked by a plugin. sor is passed from APP -> PLUGIN
-> APP (above routine). The plugin just has a pointer to work with.

What is a plugin? The objects aren't being mangled by another language
by any chance?
 
M

mark

Ian Collins said:
Pointless when it gets assigned on the next line...


What is a plugin? The objects aren't being mangled by another language
by any chance?


They shouldn't as the plugin (loadable bundle/library) only recieves a
pointer.

The plugin uses this definition:
// parent class
typedef void* SelectedObjectRef;
typedef SelectedObjectRef SORef; // shorter name

// selected file objects
typedef void* SelectedFileObjectRef; // subclass of SORef
typedef SelectedFileObjectRef SOFORef;

The plugins are not necessarily written in C++.
The test plugin is written in C.

Also, some testing shows that if the object passes through the plugin,
the casting fails. Otherwise if the casting routine is called directly
by the owning app, it succeeds. This means there is some mangling going
on somewhere.
 
J

James Kanze

[...]
The typeid.name() for '*sor' & 'SelectedFileObject' returned
'18SelectedFileObject'.
But the typeid(*sor)==typeid(SelectedFileObject) evaluates to false.

I'm just guessing, since I don't know the environment in which
you are working. But you did mention something about the actual
objects being in a plugin. So this really have nothing to do
with C++ (which doesn't support plugins, yet), but are you
loading (under Unix) or building (under Windows) the plugin
correctly, so that its symbols and types are correctly exported
and found by the main program? Or is it a case where the
SelectedFileObject in the plugin is, as far as the program can
tell, totally unrelated to the class of the same name in the
main program.

Normally, a well designed plugin will be built and loaded in a
manner such that most of the symbols in it are NOT visible
outside it---the plugin interface may very well use a type
SelectedObject, which must be common to all plugins, but you
typically don't want conflicts just because two different
plugins decide to use the same name for the derived class---you
want it to be two different classes, as if they really had
different names. And of course, if this is the case,
typeid(...).name() will return the same value for the two
different classes.
 
I

Ian Collins

mark said:
They shouldn't as the plugin (loadable bundle/library) only recieves a
pointer.

The plugin uses this definition:
// parent class
typedef void* SelectedObjectRef;
typedef SelectedObjectRef SORef; // shorter name

// selected file objects
typedef void* SelectedFileObjectRef; // subclass of SORef
typedef SelectedFileObjectRef SOFORef;

The plugins are not necessarily written in C++.
The test plugin is written in C.

Also, some testing shows that if the object passes through the plugin,
the casting fails. Otherwise if the casting routine is called directly
by the owning app, it succeeds. This means there is some mangling going
on somewhere.

Does the same pointer come out as went in, it looks like the vtable may
be getting lost.
 
M

mark

terminator said:
Is SelectedFORef castable to SOFORef ?(you have not declared the later
type.)

Really bad day for thinking yesterday.

Here's everything:

Mac OS X. XCode 2.4.

Here are the classes:

typedef class SelectedObject* SelectedObjectRef;
typedef SelectedObjectRef SORef;
typedef UInt32 SOOwnerID;

class SelectedObject {
UInt16 refCt;

SelObjectClass objectClass;
OSType ready;
protected:
SOOwnerID ID; // need to identify where the SO belongs. An SO in one
view will have
// different select flags to an SO in another view
SelObjectType objectType; // NYI
SelectionFlag selections;

static CFMutableSetRef soCache;
static void SOCacheSetProc(const void* value, void* ctx);
friend SORef CheckSOCache(SelObjectClass objClass, UInt16 objType,
SOOwnerID iID, void* data);
virtual OSStatus CheckCache(SelObjectClass objClass, UInt16 dataType,
void* data,
SORef *sor);


// the arrays are used to send one select/deselect event when a whole
lot
// of objects are selected/deselected. Sending 1000+ deselected
events is not a good
// idea
static CritRgn recentSelRgn;
static CFMutableSetRef recentlySelected;
static CFMutableSetRef recentlyDeselected;
static OSStatus PostMassSelOfOwner(SOOwnerID ID, Boolean selOrDesel,
CFArrayRef itsItems);
static OSStatus PostMassSelectEvents(SOOwnerID whichID=0); // clears
both arrays after sending
// dtEventKindObjectsSelected & dtEventKindObjectsSelected
// If zero is passed, all are sent (in seperate events for each ID)
OSStatus AddToSelected();
OSStatus AddToDeselected();

void SOCleanup();
public:
SelectedObject(SelObjectClass theObjClass, SOOwnerID ID);
SelectedObject(const SelectedObject &obj);
virtual ~SelectedObject();
UInt16 Retain();
UInt16 Release();
SelObjectClass GetObjectClass();
virtual SelObjectType GetObjectType(); // NYI. Will always return
zero.
SOOwnerID GetOwnerID();

virtual CFStringRef CopySOString();

virtual UInt64 GetSOData64(); // these two will always return zero
for the base class
virtual UInt32 GetSOData32(); // it is up to the subclasses to return
the correct values

SelectionFlag GetSelectFlags();
void DefineSelectFlag(SelectionFlag theFlags, Boolean newValue);
void ToggleSelectFlag(SelectionFlag theFlags);
Boolean IsSelectedOr(SelectionFlag whichFlags); // returns true if
any of the passed flags are set
Boolean IsSelectedAnd(SelectionFlag whichFlags); // returns true if
all of the passed flags are set
Boolean AnySelection(); // returns true is any flag is set

void PostSelectedEvent(Boolean selected);

virtual Boolean operator==(SelectedObject &obj);

virtual void DebugPrint(UInt32 v=0); // printf
virtual CFStringRef DebugString(UInt32 v=0); // CFStringRef -> CFShow
};

//-----------------------------------------------------------------------
--------------

class SelectedFileObject:public SelectedObject {
OSType sfoReady;
protected:
FSRef fsr;

virtual OSStatus CheckCache(SelObjectClass objClass, UInt16 dataType,
void* data,
SORef *sor);
void SFOCleanup();
public:
SelectedFileObject(const FSRef* fsrptr, SOOwnerID ID);
SelectedFileObject(const char* cpath, SOOwnerID ID);
SelectedFileObject(CFURLRef url, SOOwnerID ID);
SelectedFileObject(const SelectedFileObject &obj);
~SelectedFileObject();

CFStringRef CopySOString();
UInt64 GetSOData64();
UInt32 GetSOData32();
FSRef* GetFSRefPtr();
virtual CFStringRef CopyName();

Boolean operator==(SelectedFileObject &obj);

void DebugPrint(UInt32 v=0); // printf
CFStringRef DebugString(UInt32 v=0); // CFStringRef -> CFShow
};

typedef class SelectedFileObject* SelectedFORef;
typedef SelectedFORef SOFORef;

The plugin header uses this typedef:

// parent class
typedef void* SelectedObjectRef;
typedef SelectedObjectRef SORef; // shorter name

// selected file objects
typedef void* SelectedFileObjectRef; // subclass of SORef
typedef SelectedFileObjectRef SOFORef;

Here is the casting routine: (it is exported using extern "C")

SOFORef SOCastToSOF(SORef sor) {
if (sor==nil) {return nil;}
SelectedFORef sof=nil;
printf("%s\n", typeid(*sor).name()); (1)
printf("%s\n", typeid(SelectedFileObject).name()); (2)
if (typeid(*sor)==typeid(SelectedFileObject)) { (3)
sof=(SOFORef)sor;
}
else {sof=nil;}
// sof=dynamic_cast<SelectedFORef>(sor);
return sof;
};

The routine is used by plugins.
The plugins receive a SORef from the parent application via another
accessor routine and are
passed in an CFArray.
All the plugins ever receive are pointers.
The passed SORef is not guaranteed to be a SOFORef (much like a CFType
is not guaranteed to be a CFString). So they use this routine to convert
it if possible.

(1) & (2) typeid statements print '18SelectedFileObject' .
(3) always evaluates to false when the routine is called by the plugin.
But, if the owning app calls this casting routine directly, it succeeds.
Someone from a C++ newsgroup suggested that the vtable is getting 'lost'
or mangled when passed through the plugin.

Last bit of code. The CFArray callbacks:

const void* SORefRetain(CFAllocatorRef alloc, const void* value) {
SORef sor=(SORef)value;
sor->Retain();
return value;
};

void SORefRelease(CFAllocatorRef alloc, const void* value) {
SORef sor=(SORef)value;
sor->Release();
};
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,294
Messages
2,571,511
Members
48,201
Latest member
JefferyBur

Latest Threads

Top