2013-08-19 33 views
0
class GameBoy{ 

    public: 
    GameBoy() 
     :cart(new Cartridge()), 
     mmu(new MMU(cart)), 
     cpu(new CPU(mmu)) 
    {} 

    void step(); //steps through one instruction 
    const CPU::State &getCPUState() const noexcept; 
    void loadROM(std::string fileName); 

    private: 
    std::shared_ptr<Cartridge> cart; 
    std::shared_ptr<MMU> mmu; 
    std::shared_ptr<CPU> cpu; 

    }; 

我正在写一个Game Boy模拟器,这个类是Qt GUI将与之交互的。也就是说,对于在GUI中绘制的每个帧,它将调用GameBoy :: step()。显然,由于我还没有开始在GPU上工作,所以没有完成。单身人士,shared_ptr,原始指针或其他指针?

我目前在质疑这个设计,因为这3个类(Cartridge,CPU,MMU)只会被实例化一次。单身人士是否会比这更好的设计,还是现在的设计最好?

如果这一个是最好的,我应该留在shared_ptr?我已经读过,它应该谨慎使用,但在这里,这似乎是有道理的,因为所有3个类互相依赖。

非常感谢!

编辑:人们问我为什么我使用指针。从init列表中可以看到,MMU需要对Cartridge的引用,CPU需要引用MMU。

Cartridge将被GameBoy :: loadROM()和大多数MMU方法使用。我同意MMU可能不需要由GameBoy拥有,但它将在CPU和GPU之间共享(我认为)。

在下面的示例中,是否有更好的替代购物车共享指针?课间

用法示例:

byte MMU::readByte(word address) { 
      .... 
      value = cart->readROM(address); 
      .... 
     } 

void GameBoy::loadROM(std::string fileName){ 
      cart->loadROM(fileName); 
} 

编辑2:谢谢大家!我有一个最后的问题。如果GPU和CPU都使用了MMU和GameBoy的同时使用GPU和CPU,它的设计是更好:

class GameBoy{ 

public: 
GameBoy() 
: CPU(&mmu), gpu(&mmu) 
... 

private: 
MMU mmu; //never used by GameBoy 
CPU cpu; //CPU and GPU used in GameBoy 
GPU gpu; 

}; 

class CPU{ 
... 

private: 
MMU *mmu; 
}; 

class GPU{ 

... 

private: 
MMU *mmu; 

}; 

或:

class GameBoy{ 

public: 
GameBoy() 
: CPU(), gpu(&cpu.getMMU()) 
... 

private: 
CPU cpu; //CPU and GPU used in GameBoy 
GPU gpu; 

}; 

class CPU{ 
... 

private: 
MMU mmu; //arbitrarily chosen owner. GPU could have been the owner 
}; 

class GPU{ 

... 

private: 
MMU *mmu; 

}; 

我喜欢的第一个,因为它好一点似乎更一致,但GameBoy从不使用MMU。

+0

为什么共享指针? –

+0

我应该把它放在我的描述中,但正如您从init列表中看到的那样,MMU需要一个指向Cartridge的指针,并且CPU需要一个指向MMU的指针。有静态分配的对象做这个更好的方法吗? – DanB91

+0

Gameboy班是否全部使用三个? –

回答

8

我现在质疑这个设计,因为这3班 (墨盒,CPU,MMU)将只被实例化一次。

没有用户会想要说,看他们的朋友玩游戏吗?流式传输命令并在主机上模拟它们比流式传输视频具有更高的带宽效率。没有人愿意和朋友一起做“链接模式”。永远不会,先生。

也就是说,这是您的应用程序的某种基石,这实际上证明了Singleton的理由,这显然是错误的。你目前的设计和功能不要求超过这个,但有绝对没有任何理由锁定自己。其次,即使他们只能实例化一次,有史以来,这可以有效地执行一些private访问控制,绝对不需要全局状态。

简而言之,单身人士是现代编程中最糟糕的主意之一。永远不要使用一个。

如果这一个是最好的,我应该留在shared_ptr?我已经读了 它应该谨慎使用,但在这里,似乎是有道理的,因为 所有3个类互相依赖。

呃,没有。为什么要使用指针呢?只需将它们直接作为成员变量。交叉类依赖是没有理由使用shared_ptr,只是使用T *。

+0

我的计划是实际纳入在线游戏。现在,最初,我认为不需要GameBoy的另一个实例,只是来回传递数据包而没有任何抽象。现在我意识到我将使用GameBoy对象来表示第二个玩家。这是短视的。 根据我最近的编辑,如果2个对象(在这种情况下是GameBoy和MMU)共享一个对象(Cartridge),请使用原始指针?有没有理由使用shared_ptr? – DanB91

+0

@ DanB91:'shared_ptr'仅用于共享*所有权*。仅仅需要引用一个对象并不能证明使用'shared_ptr'。在这种情况下,GameBoy对象可以毫无问题地拥有mmu/cart/cpu,所以没有理由使用shared_ptr。 – Puppy

1

除了使Global对象/变量变得更加花哨之外,几乎没有理由使用Singleton。如果你发现一个好的设计来避免全局变量,那么它很容易打赌它比单例更好。

一些(可争议的)异常是记录器类或对系统中本质上可能是全局资源的资源的访问,例如共享内存。

至于使用shared_ptr与unique_ptr。坚持一个unique_ptr,除非你有一个很好的理由需要一个shared_ptr。这里它们在功能上是等价的,但unique_ptr清楚地表明Gameboy类拥有三个对象,每个对象都有一个实例。还有一些其他答案中提到,你可以完全避免指针,但是使用它们也有好处。

我应该把它放在我的描述中,但正如您从init列表中看到的那样,MMU需要一个指向Cartridge的指针,并且CPU需要一个指向MMU的指针。有静态分配的对象做这个更好的方法吗?

一种方法是抛弃初始列表,因为你的构造函数有点复杂,并明确地处理顺序。

GameBoy() 
    :cart(nullptr), 
    mmu(nullptr), 
    cpu(nullptr) 
{ 
    cart = new Cartrige(); 
    mmu = new MMU(cart); 
    cpu = new CPU(mmu); 
} 
+0

我没有得到最后一部分。成员是按照声明的顺序初始化的,所以关于顺序的确是一回事。 – chris

+0

是的,但这种方法是安全的,因为如果将声明(.h)和定义(.cpp)分开,很容易在未来的修改中扰乱顺序。在这种情况下最好明确。 – slaterade

+0

这就是对imo的评论。评论这组声明,并说不要改变顺序和原因。 – chris

0

一个好的设计可以让你同时运行多个仿真,即使这个要求在实践中从未出现过。

我想你有两个选择,取决于依赖关系的工作方式。如果mmu需要墨盒,为什么不使墨盒成为mmu的成员?而mmu是cpu的一员。或者,如果你想让他们都可以在gameboy里面进入,我认为所有三人都会和gameboy一样生活。将它们作为unique_ptr或full-members(无指针)存储在gameboy中,通过普通指针将它们传递给子类,然后在gameboy被销毁时将它们删除。

+0

删除唯一指针。他们没有理由。 –

0

变化是不变的,你应该有信心,当你想要改变你的代码时,会有一段时间。这意味着如果你目前的设计不需要需要一个单身人士,那么没有理由限制自己。当前的实现允许更多的可扩展性。

至于shared_ptr,您可以使用,当你需要多个指针指向同共享,实例。例如,假设您有3个类别ABCBC都有一个指针BC之间共享A,一个实例的一个实例,因此只应被删除后BC被删除。在那个例子中你应该使用shared_ptr。否则你应该使用unique_ptr。因此你不应该使用shared_ptr。实际上,如果cart,mmucpu是具体类,而不是接口/基类,则不应使用任何类型的指针。

编辑:

为何GameBoy类需要的CartridgeMMUCPU实例?为什么不只是一个CPU创建自己的MMU创建自己的Cartridge

+0

我可以做到这一点。但是,GameBoy需要一个加载ROM的方法。我认为说cart-> loadROM()比mmu-> loadROM()更直观。但是,也许消除指针比让代码更直观一点更好。 假设MMU需要在CPU和GPU之间共享,并且CPU拥有完整的MMU对象。难道只有这样我才能让MMU成为CPU(和GPU)中的指针吗? – DanB91

+0

您可以使用getCart() - > loadROM(),因此更容易更改getCard()以根据购物车的位置返回getMMU() - > getCart()或购物车。 – Jarod42