C ++中的被动对象

时间:2015-06-10 01:49:32

标签: c++ class struct convention

Google C ++样式guide建议将结构用于被动对象而不是类。被动对象有哪些好的用例(带示例)? 对被动对象使用结构(而不​​是类)有什么好处?

2 个答案:

答案 0 :(得分:2)

被动对象通常是不会与其他对象进行交互的对象。这方面的一个例子是一个点的数学表示:

struct Point
{
    float x, float y;
}

点在技术上不会与其他对象交互,它是被动

非被动对象将是一个使用其他对象执行任务的对象,尤其是对于函数。编写一个可以处理网络I / O的类应该是一个类,因为它将使用许多其他对象来处理套接字,地址等。我当前程序的一个简单示例:

就好处而言,拥有一个结构意味着您不需要为您的成员设置gettors / settors。除非明确定义,否则struct成员/方法是隐式public。这意味着更少的代码,以及轻微的内存改进。如果对象没有函数,则不会创建函数表。没那么大,但仍然是一个进步。您也没有函数调用的开销。

类是相反的。它们是隐式的private,只有在明确定义时才会公开。私有数据意味着您需要与所述数据交互的功能。这通常意味着将其隐藏在界面后面。这是我正在制作的IRC客户端的界面:

enum IRC_RESPONSE
{
  RSP_IGNORE = 0,
  RSP_CONTINUE,
  RSP_RET_TRUE,
  RSP_RET_FALSE,
  RSP_BREAK
};

class IRC_Client
{
public:
  //Initialize all sockets and stuff given IP, port, etc
  bool Initialize(const char *address, const int port);

  //login to server, give login info
  bool Login(const char *password, const char *nickname, const char *user);

  //disconnect
  bool Disconnect();

  //main update loop
  void Run();

  //join/leave channel
  void Join(const std::string channel);
  void Part(const std::string channel);

  //main update

private:
  // MEMBERS ////////////////////////////////////////////////////////
  SOCKET ClientSocket_;         //socket of the client
  sockaddr_in *ServerAddress_;  //address of the server
  std::string Nickname_;        //nickname of user

  // METHODS ////////////////////////////////////////////////////////
  //parsing user input to decide what to do
  bool HandleUserInput(std::string message);

  //handling any message from server
  IRC_RESPONSE HandleServerMessage(std::string message);

  //send message
  void SendMessage(std::string message);
  void SendMessage(std::string prefix, std::string command, std::string         parameters, std::string trail);

  // UTILITIES //////////////////////////////////////////////////////
  //pull nickname from prefix
  std::string GetNickname(std::string prefix);

  //parse
  void ParseServerMessage(std::string message, std::string &prefix,     std::string &command, std::string &end, std::vector<std::string> &parameters);

  // USER INPUT /////////////////////////////////////////////////////
  static void *_inputThread(void*);
};

这个课程根本不是被动的!我使用sockaddr_in之类的结构。我也使用像std::string这样的类。使这个类很好,因为我隐藏了用户的实现,以保持生活简单。

答案 1 :(得分:1)

  

被动对象有哪些好的用例(带示例)?

使用完全面向对象,封装的用户定义类型,只要面向客户端的API /功能得到尊重,开发人员就可以合理地期望能够自由添加,删除,重新排序或更改私有数据的类型。

有时候你不需要这样的封装,并且需要向开发人员强调这种自由不存在,而是在某种程度上“客户” - 无论是在同一个类的其他地方(对于嵌套类/结构)还是命名空间,实施文件,库,应用程序或IPC连接的“系统”是故意允许将自己耦合到选定的数据成员。

这可能是因为:

  • 在读取或写入内存或流时,您需要一个与所需编码匹配的特定数据表示,因为与客户有关于该数据成员或布局的协议(例如ping协议,东京证券交易所箭头标准协议,MS Excel 7.0版文档标准,一个汇编语言例程,你将调用它需要一个指向特定数据的指针,一些通过“内存”读/写访问的硬件总线)“更大”(更稳定/更长寿,官方)比任何单一的数据处理实现:数据更改的可能性极小(或不可能 - 您不能追溯性地更改Excel版本使用的数据格式)和/或您准备好的基础让你的程序中断,并且必须重新访问数据的所有用途来修复它。

  • “客户端”使用的范围相对较小(例如,嵌套在另一个中的私有类/结构,或实现文件中的匿名命名空间中的一个),这样如果数据的返工有限则更改,并且网络代码编写/维护/可理解性受益于公共数据成员的简单性和简洁性,并避免访问说明符和简单的get / set函数。

一个例子:一个Weighted_Average类,内部保存了许多样本的列表,其中包含捕获它们时的时间戳 - 它可能会合理地将数据类型的实例与timeval一起混为一谈或std::chrono::time_pointstructvector可用于实例化liststruct

  

对被动对象使用结构(而不​​是类)有什么好处?

具有最小的功能优势(唯一的语言区别在于对基础和成员的默认访问,这使得struct更简洁,如果您想要这样的公开)。

Google风格指南的动机在其中清楚表达:

  

我们为每个关键字添加自己的语义含义

这只是说他们使用class vs class来编码某个类型是否是被动的(根据他们的定义)。

更一般地说,许多编码样式使用struct vs struct的选择来编码类型的封装级别的一些模糊相似的方面。就个人而言,Google指南未明确允许我使用Hash的许多案例,例如:

  • 从抽象观察者派生一个具体的观察者,同时覆盖各种事件的虚拟回调,其中观察者对其所使用的类是私有的

  • 编写简单的无状态仿函数(例如Equalstd::unordered_map用于实例化struct Impl;)或谓词

  • the pImpl Idiom

  • 的私人struct

此外,我根据我准备让客户拥有的依赖关系/耦合来决定,这与struct是否会有更复杂的成员函数无关。我认为Google没有理由限制struct成员函数,因为这些函数没有强制执行后置条件或不变量,因为数据成员可以直接访问这些条件或不变量。换句话说 - 只要函数调用后struct timeval { int64_t tv_sec, tv_usec; };的数据良好,谁关心函数是否正常。举一个具体的例子,如果给normalise() tv_usec函数确保tv_sec在[0..1,000,000]微秒范围内并且有时相应地调整{{1}},那么好的:它不会干扰数据的任何其他用途。