2010-02-19 77 views
2

在我的游戏引擎中,我有一个代表游戏世界的状态类。该状态包含许多Body对象,每个对象都定义一个刚体。每个状态都有一个容器来跟踪它拥有的Body对象,并且每个Body都有一个指向其父状态的指针。容器关系和封装

纲要州级:

class State { 
private: 
    std::set<Body*> _bodies; 

public: 
    //It could be done here 
    void addBody(Body* body) { 
    //Remove from old State 
    if (body->_state) 
     body->_state->_bodies.erase(this); 

    //Set Body's back-reference 
    body->_state = this; 

    //Add to this State 
    _bodies.insert(body); 
    } 
}; 

体类概况:

class Body { 
private: 
    State* _state; 

public: 
    //It could also be done here 
    void setState(State* state) { 
    //Remove from old State 
    if (_state) 
     _state->_bodies.erase(this); 

    //Set back-reference 
    _state = state; 

    //Add to the new State 
    if (_state) 
     _state->bodies.insert(this); 
    } 
}; 

的问题,如果有一个,就是添加/删除一个机构/从一个国家需要改变每个人的私人成员。

有一次,我考虑有一个状态 - 介体静态类,它有朋友访问这两个类。这听起来不错,因为状态与身体的关系将由这个名字明确地管理,但是对于管理一个简单的关系来说,这是很多的声明开销。

有没有“更好”的方法来做到这一点?我想看看那里有什么想法。

回答

1

嗯,你可以做这件事是有两个类的友元函数:

void associate(State& s, Body& b) 
{ 
    s.addBody(&b); 
    b.setState(&s); 
} 
+0

这是真的,没有任何理由,每个关系管理功能必须在一个单独的类。 – mvanbem 2010-02-19 17:37:52

0

在第一遍,我将两种方法结合起来:

void State::addBody(Body* body) { 
    //Add to this State 
    bodies_.insert(body); 

    //Remove from old State 
    body->setState(this); 
} 

void State::removeBody(Body* body) { 
    bodies_.erase(body); 
} 


void Body::setState(State* state) { 
    if(state_) { 
     state_->removeBody(this); 
    } 
    state_ = state; 
} 

这将国家和机构的内部分离开来,所以你可以例如对状态的身体列表使用一些完全不同的机制,并且身体不需要知道它。你会想要小心异常安全;这个例子有意将容器插入开始,所以如果抛出,对象的状态不会改变,但我不确定这里没有其他东西可以抛出。

请注意,我将下划线移到了成员变量的末尾;我知道主要的下划线是一个常见的约定,但它们实际上是由C++标准保留给编译器的。

+0

那么,只要没有大写字母,实际上前面的下划线都可以。不过,由于我自己的审美原因,我更喜欢尾随的下划线。 – rlbond 2010-02-19 23:47:14

0

私人的目的是要有一个类负责维护身体 - 国家联系。实际效果是,当联系出现问题或需要以某种方式加强时,您只有一个班级进行检查或修改。你可以用朋友来分担责任,但是你可能会为自己长期头痛。我会保留一个或两个班的“哑巴”。

// example 1: dumb state 
void State::addBody(Body* body) { _bodies.insert(body); } 
void State::removeBody(Body* body) { _bodies.erase(body); } 
void Body::setState(State* state) 
{ 
    if(_state) _state->removeBody(this); 
    if(state) state->addBody(this); 
    _state = state; 
} 

// example 2: dumb body 
void Body::setState(State* state) { _state = state; } 
State* Body::getState() const { return _state; } 
void State::addBody(Body* body) 
{ 
    if(body && body->getState() != this) 
    { 
     body->getState()->_bodies.erase(body); 
     _bodies.insert(body); 
     body->setState(this); 
    } 
} 

// example 3: both are dumb 
void State::addBody(Body* body) { _bodies.insert(body); } 
void State::removeBody(Body* body) { _bodies.erase(body); } 
void Body::setState(State* state) { _state = state; } 
State* Body::getState() const { return _state; } 
void BodyStateMachine::setBodyState(Body* body, State* state) 
{ 
    if(body && body->getState() != state) 
    { 
     body->getState()->removeBody(body); 
     state->addBody(body); 
     body->setState(state); 
    } 
} 

您选择的方法应该取决于哪个类将更公开使用(您更希望其他代码管理“智能”类)。你可以通过创建一个不暴露getter/setter函数的接口来进一步保护哑类。