为同基类派生类实现碰撞检测:保护成员访问问题咨询
你现在遇到的问题是:虽然Bullet和Zombie都继承自MovingObject,但Bullet无法直接访问Zombie对象的x、y成员——这是C++保护成员(protected)的访问规则导致的:派生类只能访问自身继承来的基类保护成员,不能访问另一个派生类对象的基类保护成员。也就是说,Bullet可以用this->x访问自己的位置,但不能直接用pZombie->x访问僵尸的位置,哪怕x是基类的protected成员。
下面给你两种符合要求的实现方向,都是不用写单独的getter方法的:
方案1:让基类提供跨对象的距离计算方法
既然基类本身可以访问任意MovingObject对象的protected成员(因为这些成员属于基类自己),我们可以在MovingObject里添加一个保护成员函数,专门计算当前对象和另一个MovingObject的距离:
class MovingObject { protected: double x; double y; double speed; double damage; // 原有的私有distance函数可以保留 double distance(double x1, double y1, double x2, double y2) { return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)); } // 新增:计算当前对象和另一个MovingObject的距离 double distanceTo(MovingObject* other) { return distance(x, y, other->x, other->y); } public: MovingObject(double x, double y, double speed, double damage); virtual bool isCollide(MovingObject* Object); virtual void draw() {}; virtual void move() {}; };
然后在Bullet的碰撞检测里,直接调用这个方法就可以了:
bool Bullet::isCollide(Zombie* pZombie) { if (distanceTo(pZombie) < 10) { pZombie->getHit(); return true; } else { return false; } }
这个方案既符合封装原则,又不用写单独的getter,是比较推荐的做法。
方案2:将派生类互相声明为友元(不推荐但可行)
如果你想更直接地访问对方的成员,可以在Zombie类里声明Bullet为友元,这样Bullet就能访问Zombie的所有成员(包括继承来的x、y):
class Zombie : public MovingObject { // 声明Bullet为友元 friend class Bullet; private: double hpMax; double hpCurrent; double attackCD; double attackRate; public: // 构造函数和其他成员不变 Zombie(double x, double y, double speed, double damage, double hpMax, double hpCurrent, double attackCD, double attackRate); bool isCollide(Bullet* pBullet); void draw(); void move(); void getHit(); void drawHPBar(); void decreaseAttackCD(); void refreshAttackCD(); };
这样你的原代码就能直接访问pZombie->x和pZombie->y了。不过这种方法会破坏类的封装性,一旦后续修改类的成员,友元类的代码可能会受影响,所以只适合简单场景快速验证。
作为刚接触OOP的新手,尽量优先选择方案1——通过基类提供公共/保护接口来实现跨对象的成员访问,这能更好地体现面向对象的封装思想,让代码更易维护。
内容的提问来源于stack exchange,提问作者İlker Zeybek

