我假设您已经测量并确认了虚拟函数调用的成本或增加的对象大小使得这样做是可取的。或者您可能只是认为模板设计更好。
通过 CRTP 进行继承
如果你想使用继承,你可以使用奇怪的重复模板模式(CRTP) https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern。您有一个模板化的 Player 基类,其中模板参数是派生类:
template<class Derived>
class Player {
public:
void play()
{
auto& derived = static_cast<Derived&>(*this);
for (int i = 0; i < derived.getNumChunks(); i++)
{
if (derived.chunkHasX(i) || derived.chunkHasY(i))
derived.playChunk(i);
}
}
};
class DerivedPlayer : public Player<DerivedPlayer> {
private:
friend class Player<DerivedPlayer>;
int getNumChunks();
bool chunkHasX(int chunkIndex);
bool chunkHasY(int chunkIndex);
void playChunk(int chunkIndex);
};
int main() {
DerivedPlayer p;
p.play();
}
现场演示 https://wandbox.org/permlink/kVh9KJ5dUR8m2C4d.
作品
或者也许您可以使用组合而不是继承并组合您的Player
of a ChunkHolder
它作为模板参数传递:
template<class ChunkHolder>
class Player {
private:
ChunkHolder chunk_holder;
public:
void play()
{
for (int i = 0; i < chunk_holder.getNumChunks(); i++)
{
if (chunk_holder.chunkHasX(i) || chunk_holder.chunkHasY(i))
chunk_holder.playChunk(i);
}
}
};
class MyChunkHolder {
public:
int getNumChunks();
bool chunkHasX(int chunkIndex);
bool chunkHasY(int chunkIndex);
void playChunk(int chunkIndex);
};
int main() {
Player<MyChunkHolder> p;
p.play();
}
现场演示 https://wandbox.org/permlink/G4sDxRCrw9KCmCyU.
Update:Russ Schultz 的评论提醒我,如果你想多态地对待这些不同的玩家,你可以。简单介绍一个接口:
class IPlayer {
public:
virtual ~IPlayer(){}
virtual void play() = 0;
};
然后在这两种情况下你都可以继承这个接口并覆盖play()
功能:
template<class T>
class Player : IPlayer {
public:
void play() override;
};
例如,现在您可以将玩家放入一个容器中,但不会通过在内部循环中调用虚拟函数来影响性能。
现场演示CRTP https://wandbox.org/permlink/bD9p0aOUIJmXRK3Z and 作品 https://wandbox.org/permlink/3Hdg1PPTqAQiFqqa.