具有公共成员对象的班级组成

Class composition with public member objects

本文关键字:成员对象      更新时间:2023-10-16

我正在尝试找出设计我的程序功能的最佳方法。

该程序的主要组成部分是相机类。该相机对象表示程序用户界面与真实摄像机的界面,该摄像头通过框架抓取卡将其连接到计算机。相机类可以链接到框架抓取器,启动和停止获取,还可以突变/访问许多不同的相机属性。当我说很多时,我谈论的是超过250个独特的命令。每个唯一的命令都通过将串行串通过框架夹发出到物理摄像头来发出相机。每个命令都可以被认为是三种类型之一。动作,查询和值。

一个动作命令是不需要等等的东西

查询是您可以获得但不设置的东西,通常与值相关。例如"温度=?"," sernum =?"," maxframerate =?"命令会导致相机发送回到信息。这些值无法突变,因此"温度= 20"会导致错误。

值是您可以获得和设置通常与值关联的值。例如" Framerate = 30"answers" Framerate =?"是两个唯一的命令,但我认为基本字符串" Framerate"是一种值命令类型,因为它可以被突变和访问。

250个唯一的命令可以减少到约100个相机,相机Querquerys和Cameravalues。我没有在相机类中使用250种方法,而是想组成命令对象,而不是单个设置器,获取器和操作。命令字符串可以在构造函数中提供,也可以用设置器重置。然后,我可以撰写一个包含所有可用命令的cameracommands对象,并作为我相机的公共成员提供。

//CameraAction.h =============================================
class CameraAction {
public:
  CameraAction(std::string commandString, SerialInterface* serialInterface);
  void operator()() { _serialInterface->sendString(_commandString); }
private:
  SerialInterface* _serialInterface;
  std::string      _commandString;
}; 

//CameraValue.h =====================================================
class CameraValue {
public:
  CameraValue(std::string commandString, double min, double max, SerialInterface* serialInterface);
  void set(double value)
  {
    if(value > _maxValue) { throw std::runtime_error("value too high"); }
    if(value < _minValue) { throw std::runtime_error("value too low"); }
    std::string valueString = std::to_string(value);
    _serialInterface->sendString(_commandString + "=" + valueString);
  }
  double get()
  {
    std::string valueString = _serialInterface->sendString(_commandString + "=?");
    return atof(valueString.c_str());
  }
private:
  SerialInterface* _serialInterface;
  std::string      _commandString;
  double           _minValue;
  double           _maxValue;
};  

//CameraCommands.h ===================================================
class CameraCommands {
public:
  CameraCommands();
  CameraAction reset;
  CameraQuery  temperature;
  CameraValue  framerate;
  CameraValue  sensitivity;
  //... >100 more of these guys
};

//Camera.h ===========================================================
class Camera {
public:
  Camera();
  CameraCommands cmd;
  void startAcquisition();
  void stopAcquisition();
  void setDataBuffer(void* buffer);
  void setOtherThing(int thing);
};

以便用户可以做类似的事情:

Camera myCamera;
myCamera.cmd.reset();
myCamera.cmd.framerate.set(30);
myCamera.cmd.sensitivity.set(95);
double temperature = myCamera.cmd.temperature.get();
myCamera.startAcquisition();

等...

这里的主要问题是我正在揭露公共成员变量,这应该是一个巨大的禁忌。是我当前的对象设计逻辑,还是我应该简单地实现250个固定器和盖特特,还有100个固定器和Getters来突变最小和最大可设置值。

对我来说这似乎是kludgey,因为与用户命令无关的相机对象相关的固定器/获取器。用户界面提供方法(CMD)的范围是很好的,以便用户知道是否在相机中进行物理突变,还是只是在程序化对象中突变(其他方法)。有什么更好的方法设计我的程序吗?

您基本上描述了一个有趣的层次结构:

Command-> Query-> Value

  • a Command保留是命令文本的字符串;它还可以为其孩子提供protected Send()方法。
  • a Query还可以立即持有(protectedint变量(或其他可以立即get()和/或operator int()),或者来自相机中的query();
  • A Valueset()和/或operator =(int)命令添加到Query

Value的构造函数(特别是)可以具有minmax

Camera对象可以具有许多public成员:

class Camera {
private: // Classes that no-one else can have!
    class Command; friend Command;
#include "Camera.Command.inc"
    class Query; friend Query;
#include "Camera.Query.inc"
    class Value; friend Value;
#include "Camera.Value.inc"
public: // Variables using above classes
    Command reset;
    Command open;  // Maybe make this one private, for friends?
    Command close; // Ditto?
    Query temperature;
    Query sernum;
    Query maxFrameRate;
    Value frameRate;
private: // Variables
    SerialPort port; // Allow Command and co. access to this
}; // Camera

通过这样组织,然后:

  • 变量的用户无法提出不可能的请求 - 没有任何方法;
  • query()set()方法隐藏了与物理摄像机接口的机制。

您会注意到我已经在Camera类的中间添加了#include "Camera.XXX.inc"。注意:

  1. 它不会用这些子类的定义来混乱相机类 - 但是C 编译器需要它们在使用它们之前需要它们,因此您需要将它们放在那里。如果您想知道他们的工作,请打开文件!
  2. 我给了他们.inc扩展程序,因为它们在.h文件中"包括":它们不单独作为自己的标头文件。

您可以使用一个或多个结构来分组"设置",然后公开一种方法来设置它们:

typedef struct settings{
  int setting1;
  int setting2;
}MySettings;
class Myclass{
 private :
   int setting1;
   int setting2;
 public Myclass(MySettigs *settings)
{
  if(null != settings){
     setting1=settings->setting1;
     setting2=settings->setting2;
  }
}
public void ChangeSettings (MySettings *setting){
  if(null != settings)
  {
     setting1=settings->setting1;
     setting2=settings->setting2;
  }
}
public void TakeSettings (MySettigs *settings){
  [copy local variables into the passed struct]
}

我强烈建议在对象"操作"时更改设置时要小心。

在您提到的设计中,我不认为通过构图展示公共成员是一个很大的禁忌。

公开公共成员时,大否-NO是不安全的访问您的课程内部。

一个示例将允许公众访问CameraValue::_maxValue。用户可以将该值更改为任何事物,从而导致各种不确定的行为。

是否由我设计,我不会有CameraCommands成员,因为从外观上看,它不会添加其他任何东西,而是间接级别。

我要么将所有CameraActionCameraValue成员作为相机类的一部分,要么继承。

类似的东西:

CameraCommands合并到Camera中:

class Camera 
{
public:
  Camera();
  CameraAction reset;
  CameraQuery  temperature;
  CameraValue  framerate;
  CameraValue  sensitivity;
  //... >100 more of these guys
  void startAcquisition();
  void stopAcquisition();
  void setDataBuffer(void* buffer);
  void setOtherThing(int thing);
};

CameraCommands继承到Camera

class Camera : public CameraCommands
{
public:
  Camera();
  void startAcquisition();
  void stopAcquisition();
  void setDataBuffer(void* buffer);
  void setOtherThing(int thing);
};

您甚至可以为CameraValue等提供一些操作员,以便您可以通过分配设置值(operator=),并通过隐式转换(operator T)或删除性(operator*)获取值:

template<typename T>
class CameraValue
{
public
    CameraValue(SerialInterface*, std::string cmd);
    CameraValue& operator=(const T& val)
    {
        _val = val;
        std::string val_str = std::to_string(_val);
       _ser_ifc->sendString(_cmd + "=" + val_str);            
    }
    const T& get() const
    {
        return _val;
    }
    // implicit access to _val
    operator const T&() const
    {
        return _val;
    }
    // dereference operator to access _val
    const T& operator*() const
    {
        return _val;
    }
private:
    T _val;
    SerialInterface* _ser_ifc;
    std::string      _cmd;
};

然后在类中使用CameraValue如下:

using CameraFramerate = CameraValue<int>;
CameraFramerate framerate;

上述技术提供(IMO)Camera的更合并的用法,例如以下内容:

Camera camera;
// setting values
camera.framerate = 30;
camera.sensitivity = 95;
// getting values
int framerate =  camera.framerate; // uses operator T&()
int framerate = *camera.framerate; // uses operator*()

这里的关键是Camera::framerate等不允许任何可以以不确定和/或不安全方式更改相机类的内部状态的访问。