问题
Here is a code:
class Base {
public:
long index;
};
class Derived : public Base {
public:
bool value;
};
void call(map<char *, Base *> *base) {
map<char *, Base *>::iterator it = base->begin();
cout << it->second->index << endl;
}
void test(void) {
map<char *, Derived *> *d = new map<char *, Derived *>;
call(d);
}
Compiler alerts an error:
error C2664: 'call' : cannot convert parameter 1 from 'std::map<_Kty,_Ty> *' to 'std::map<_Kty,_Ty> *'
1> with
1> [
1> _Kty=char *,
1> _Ty=Derived *
1> ]
1> and
1> [
1> _Kty=char *,
1> _Ty=Base *
1> ]
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
I understand why this error is happened. I do not understand how to make it work. What kind of cast and how to use it?
UPD
I'm sorry for imprecision, let me explain more details. I have two sets of data represented by ClassA and ClassB. Both of these classes have one common member - an "index", for example. Both sets are wrapped into a maps (special thanks to Rob for a significant correction with char*):
std::map<char, ClassA>
std::map<char, ClassB>
Sometime I need to iterate over both maps to get a value of a common member "index". I'm trying to avoid code duplication and make just one function to iterate over both maps.
I thought I may extract a superclass with a common member and make a function with parameter like this one:
std::map<char, SuperClassAB>
or
std::map<char, SuperClassAB>::iterator
But looks like it's a bad idea.
UPD2
One smart guy gave me the solution:
template <class T>
void call(map<char, T> *base) {
map<char, T>::iterator it = base->begin();
cout << it->second->index << endl;
}
void test(void) {
map<char, Derived *> d;
call(&d);
}
回答1:
No one seemed to suggest this yet, but you could also make call
a function template.
template <class Type>
void call(const std::map<char*,Type*> & base)
{
static_assert(std::is_base_of<Base, Type>::value,
"Function is only callable with maps "
"whose mapped_type is derived from Base");
/* More stuff */
}
This way the function is callable with Base
, Derived
and anything else that derives from Base
.
回答2:
You can't cast these types. map<char*,Base*>
and map<char*,Derived*>
are as different as string
and float
.
Simplest thing to do is within test()
simply populate a map<char*,Base*>
and call call
with that. Provide virtual
methods in Base
(possibly pure virtual
), and implement those functions in Derived
.
You could attempt to transform
a map<char*,Derived*>
from a map<char*,Base*>
, but in order to do so your functor would need to either:
- Absolutely know that the
Base*
actually points to aDerived
object, and usestatic_cast
. - Make
Base
polymorphic (usually by implementing avirtual
destructor), and usedynamic_cast
回答3:
If your goal is to "operate" in some way on the derived class, create a virtual method on the base class and override it to get the specific behavior you want:
class Base
{
public:
long index;
virtual void doSomething()
{
// Do something with index
cout << index << endl;
}
};
class Derived : public Base
{
public:
bool value;
virtual void doSomething()
{
// Do something with value
cout << value << endl;
}
};
// NOTE: I removed the pointer and made it a ref.
// NOTE: I made it "const" because you probably don't want to alter the
// map. If you do...
void call(const map<char *, Base *>& base)
{
map<char *, Base *>::const_iterator it = base.begin();
// cout << it->second->index << endl;
it->second->doSomething();
}
void test(void)
{
map<char *, Base *> d;
// Push some members into d...I didn't, but you should
// if you want call(...) to be meaningful.
call(d);
}
Was this helpful?
回答4:
You probably need your container to store base class pointers instead of derived class pointers.
E.g.map<char *, Base *> *d;
.
Thereafter, you should populate the map with elements of whatever derived types you want. E.g.
char keyA = 'A';
char keyB = 'B';
(*d)[&keyA] = new Derived();
(*d)[&keyB] = new AnotherDerived();
Would that work in your instance?
As an aside, why are you using char *
as the key seems like an odd choice.
来源:https://stackoverflow.com/questions/20761457/inheritance-in-stdmap-with-base-class-as-value