条款31:让函数根据一个以上的对象型别来决定如何虚化
如果函数有两个自变量,而这两个自变量都是继承类,我们如果根据排列组合的办法来实现继承类。RTTI或者只使用虚函数?似乎都不是好办法。Meyers给出的解决方案是自行仿真虚函数表格(Virtual Function Tables)
考虑如下代码:
#include
<
string
>
#include
<algorithm>
#include
<
iostream
>
#include
<
map
>
#include
<typeinfo>
using
namespace
std
;
class
GameObject
{
public
:
GameObject
(){}
virtual
~
GameObject
(){}
protected
:
private
:
};
class
SpaceShip
:
public
GameObject
{
public
:
SpaceShip
(){};
virtual
~
SpaceShip
(){}
protected
:
private
:
int
i
;
};
class
Station
:
public
GameObject
{
public
:
Station
(){}
virtual
~
Station
(){}
};
class
Asteriod
:
public
GameObject
{
public
:
Asteriod
(){}
virtual
~
Asteriod
(){}
};
void
shipAsteriod
(
GameObject
&
spaceShip
,
GameObject
&
asteriod
)
{
printf
(
"shipAsteriod/n"
);
}
void
shipStation
(
GameObject
&
spaceShip
,
GameObject
&
station
)
{
printf
(
"shipStation/n"
);
}
void
asteriodStation
(
GameObject
&
asteriod
,
GameObject
&
station
)
{
printf
(
"asteriodStation/n"
);
}
void
asteriodShip
(
GameObject
&
asteriod
,
GameObject
&
spaceShip
)
{
shipAsteriod
(
spaceShip
,
asteriod
);
}
void
stationShip
(
GameObject
&
station
,
GameObject
&
spaceShip
)
{
shipStation
(
station
,
spaceShip
);
}
void
stationAsteriod
(
GameObject
&
station
,
GameObject
&
asteriod
)
{
asteriodStation
(
asteriod
,
station
);
}
typedef
void
(*
HitFunctionPtr
)(
GameObject
&,
GameObject
&);
typedef
map
<
pair
<
string
,
string
> ,
HitFunctionPtr
>
HitMap
;
HitMap
*
initializeCollisionMap
();
HitFunctionPtr
lookup
(
const
string
&
class1
,
const
string
&
class2
);
pair
<
string
,
string
>
makeStringPair
(
const
char
*
s1
,
const
char
*
s2
);
void
processCollision
(
GameObject
&
obj1
,
GameObject
&
obj2
)
{
HitFunctionPtr
phf
=
lookup
(
typeid
(
obj1
).
name
(),
typeid
(
obj2
).
name
());
if
(
phf
)
{
phf
(
obj1
,
obj2
);
}
else
throw
exception
();
}
pair
<
string
,
string
>
makeStringPair
(
const
char
*
s1
,
const
char
*
s2
)
{
return
pair
<
string
,
string
>(
s1
,
s2
);
}
HitMap
*
initializeCollisionMap
()
{
HitMap
*
phm
=
new
HitMap
;
(*phm)[makeStringPair(typeid(SpaceShip).name(),typeid(Asteriod).name())] = &shipAsteriod;
(*phm)[makeStringPair(typeid(SpaceShip).name(),typeid(Station).name())] = &shipStation;
(*phm)[makeStringPair(typeid(Station).name(),typeid(Asteriod).name())] = &stationAsteriod;
(*phm)[makeStringPair(typeid(Station).name(),typeid(SpaceShip).name())] = &stationShip;
(*phm)[makeStringPair(typeid(Asteriod).name(),typeid(SpaceShip).name())] = &asteriodShip;
(*phm)[makeStringPair(typeid(Asteriod).name(),typeid(Station).name())] = &asteriodStation;
return
phm
;
}
HitFunctionPtr
lookup
(
const
string
&
class1
,
const
string
&
class2
)
{
static
auto_ptr
<
HitMap
>
collisionMap
(
initializeCollisionMap
());
HitMap
::
iterator
iter
=
collisionMap
->
find
(
makeStringPair
(
class1
.
c_str
(),
class2
.
c_str
()));
if
(
iter
==
collisionMap
->
end
())
return
0;
return
iter
->
second
;
}
int
main
(
int
argc
,
char
*
argv
[])
{
SpaceShip
ship
;
Asteriod
ast
;
Station
s
;
processCollision
(
ship
,
ast
);
processCollision
(
ast
,
ship
);
processCollision
(
s
,
ship
);
processCollision
(
ship
,
s
);
processCollision
(
ast
,
s
);
processCollision
(
s
,
ast
);
return
0;
}
这是一个用RTTI来实现的Virtual Function Table的仿真,那么在这个Function Table中,只需要加入合适的函数指针到map中去就可以了。千万注意的是,如果想支持RTTI,并须有虚函数存在才可以,否则……。我开始就犯了这个错误。