问题
I found that dynamic_cast
didn't work in a situation where I expected it to, and looking at the typeid
of the objects at runtime has made the situation even less clear. I just want a cast from base to derived, and I can't figure out why it's not working.
I have a class structure something like this:
class BoundaryCondition {
public:
virtual void DoSomething() = 0;
virtual ~BoundaryCondition() { /* * */ }
}
class ReflectingBc : BoundaryCondition {
public:
virtual void DoSomething();
}
class MarshakBc : BoundaryCondition {
public:
virtual void DoSomething();
MarshakBc(double value);
void changeValueLaterOn(double value);
private:
double value_;
}
I have (essentially) a std::vector<BoundaryCondition*>
that represents boundary conditions in parts of the problem. I want to be able to take that vector
and, for all MarshakBc
objects inside it, call changeValueLaterOn
. So I have a loop that looks like
for (std::vector<BoundaryCondition*>::iterator bc = bcPtrs_.begin();
bc != bcPtrs_.end(); ++bc)
{
if (std::string(typeid(MarshakBc).name()) == std::string(typeid(**bc).name()) )
{
std::cerr << "SAME! ";
}
if (typeid(MarshakBc) != typeid(**bc))
{
std::cerr << "NOT SAME ";
}
MarshakBc* thisBc = dynamic_cast<MarshakBc*>( &( **bc ) );
if (thisBc == NULL) {
std::cerr << "...nothing\n";
continue;
}
thisBc->changeValueLaterOn( 1.23);
std::cerr << "...set!\n";
}
If my vector contains a ReflectingBc*
, then a MarshakBc*
, my output looks like:
NOT SAME ...nothing
SAME! NOT SAME ...nothing
Am I misunderstanding something about dynamic_cast
and typeid
?
[The actual situation is more complicated than this because the definition of BoundaryCondition
is in a different translation unit than the above code, and templates and such are involved, but the above code is very representative of what I'm doing and the result I'm getting.]
More details
Here is my actual routine, which is used inside a functor, and LoAnisoBc
is the derived class and BoundaryConditionT
is the base class:
template<class SnTraits_T, class LoTraits_T>
void FillLoAnisoBcs<SnTraits_T, LoTraits_T>::operator() (
const BoundaryFaceT& bf,
BoundaryConditionT& bc)
{
std::cerr << "Want " << typeid(LoAnisoBc).name() << "\n";
std::cerr << "Chkg " << typeid(bc).name() << "\n";
if (std::string(typeid(LoAnisoBc).name()) == std::string(typeid(bc).name()) )
{
std::cerr << " SAME!";
}
if (!(typeid(LoAnisoBc) == typeid(bc))) {
std::cerr << "...nothing\n";
}
// if we're not an "anisotropic BC", don't do anything
LoAnisoBc* anisoBc = dynamic_cast<LoAnisoBc*>( &bc );
if (anisoBc == NULL) {
std::cerr << "...nothing\n";
return;
}
anisoBc->setFCoeff( fCoeff_ );
std::cerr << "; set fCoeff = " << fCoeff_ << "\n";
}
And here's the output
Want N6detLib17cellDiffusionOned28AnisotropicBoundaryConditionE
Chkg N6detLib17cellDiffusionOned27ReflectingBoundaryConditionE
NOT SAME...nothing
Want N6detLib17cellDiffusionOned28AnisotropicBoundaryConditionE
Chkg N6detLib17cellDiffusionOned28AnisotropicBoundaryConditionE
SAME! NOT SAME...nothing
So the bcPtrs_
structure and the boundary conditions are in one dynamic library (so it's one module in Python), and the instantiation of FillLoAnisoBcs
is in another dynamic library. Erik suggests this as the probable issue and I agree.
回答1:
typeid
behaves strangely when you're crossing library boundaries - See e.g. When can typeid return different type_info instances for same type? for some cases. In particular, on linux you will need -rdynamic
to ensure that type info objects from a library aren't removed, and thus inaccessible to the executable using the library.
My best guess at an explanation:
In the executable, where you see the LoAnisoBc
definition, a type_info
instance for LoAnisoBc
exists. In the library, where LoAnisoBc
"belongs", another type_info
instance exists. type_info
's operator==
is likely implemented as a simple pointer comparison. So, when you get typeid of the static LoAnisoBc
expression you get the executable instance, whereas the reference produces the library instance - same name but not same instance.
来源:https://stackoverflow.com/questions/5652209/dynamic-cast-issues-typeid-object-is-not-equal-but-name-is-equal