具有一般和专业属性的课程

Class with general and specialized attributes

本文关键字:属性 具有一      更新时间:2023-10-16

如何基于类型对一类建模类别和特定属性。例如,我有一个原始类。原始类具有以下一般成员:原型,翻译,旋转,以及基于原始类型的其他字段。

enum PrimitiveType
{
   CYLYNDER,
   CUBE,
   CONE
}
class Primitive
{
   string name;
   PrimitiveType type;
   double positionX,positionY,positionZ;
   double rotationX,rotationY,rotationZ;
  // following members are if primitivetype is CYLYNDER
   double height;
   double radius;
  //following members are if primitive is CUBE
  double height;
  double width;
  double length;
};

我当然可以继承,并制作从原始的原始和cylynder and Cube类。但是课程之间没有自己之间的多态关系,因此我不使用继承。我需要它们只是具有属性的普通结构。

我还可以制作成分,并制作具有原始成员的cylynder and Cube类。但是我需要将Cylynder,Cube和Cone的对象存储在一个向量中。因此,如果我做组成,我将如何将它们存储在一个std :: vector中。

我基本上需要以某种方式对结构进行建模,以便满足以下要求:

1)将不同类型组件的对象存储在一个std :: vector

2)将不同类型的对象存储在简单可读且可编辑的配置文件中。 在配置文件中,我只想保存与原始类型的特定类型相关的专门属性,而不是所有原始类型的专用属性。 因此,我想在配置文件中获得这样的东西:

<Primitive>
 <name>Primitive1</name>
 <type>CYLYNDER</type>
 <positionx>0</positionx>
 <!-- other common attributes here, omitted to save space -->
 <!-- specific primitive type attributes -->
 <height> 10 </height>
 <redius>5</radius>
</Primitive>
<Primitive>
  <name> Primitive2 </name>
  <type> CUBE </type>
  <positionx>0</positionx>
  <!-- other common attributes here, omitted to save space -->
  <!-- specific primitive type attributes -->
  <height>10</height>
  <width>10</width>
  <length>10</length>
</Primitive>

您有很多选择,例如:

  • 创建三个不同的类,并在vector中存储boost::variant<Cylinder, Cube, Cone> S(从概念上讲,这是一个歧视的联合,但是boost::variant为您清理并处理丑陋的边缘案例(例如对齐)

    • 如果需要,您仍然可以为共享成员/功能使用构图
  • 创建一个带有枚举和"胖"界面和字段的类(当您开始进行上方执行时,但将副本以"//为"//"为"许多原语"组)

    • hackish且纠结
  • 使用多态性 - 当然,似乎会有一些常见的功能子集可以暴露出来,虽然丑陋的dynamic_cast<>支持运行时型特定于运行时型切换

    • 您的"没有自身之间的多态关系,所以我不使用继承" 不是避免这种关系的令人信服的理由,因为您声称需要将类型存储在单个vector <</li>

至于从文件内容创建对象...您需要的东西称为"工厂" - 它可以从配置文件中读取PrimitiveType,然后调用特定于特定于类型的字段进行放松,最后是构造代码。

这可能对您的案件过大,但是我习惯于处理专有API中无法使用boost::variant之类的专有API中的此类问题,以避免公众依赖(要求插件作者安装了提升),并允许变体类型扩展伪折扣处的受支持类型的范围(例如:来自应用程序中间的Dylib插件)。拥有一个通用的构建块将非雄激素类型变成同质的东西是有帮助的,能够存储在一个容器中,均匀访问等。

当您想要这些类型的运行时属性系统和反射以及类型之间的一定层次的同质性时,C 的静态性质可能会使它变得有些困难。该语言并不能使您有必要在蝙蝠中做这类事情的手段。如果您有严格的ABI限制,这特别棘手。

如果您对这种滚动袖子专有的解决方案感兴趣,则第一个构建块是一个穷人的rtti,在模块边界上工作:

// Implemented at a central core level.
int to_type_code(const char* type_name);
// Registers a new type with the system.
// Thread safety omitted here for the sake of simplicity.
#define REGISTER_TYPE(type) 
    template <> inline 
    int type_code<type>() 
    { 
        static const int val = to_type_code(#type); 
        return val; 
    }
// Example usage:
REGISTER_TYPE(bool);
REGISTER_TYPE(char);
REGISTER_TYPE(short);
REGISTER_TYPE(int);
// etc

现在,您可以从任何模块中执行type_code<int>()之类的事情,并获得相同的结果。这为我们提供了一些可以映射特定于类型功能的功能,例如系统遇到给定类型时要显示的GUI控件/小部件(允许您自动从数据中生成GUI,尤其是在与反射结合使用时方便),需要功能才能序列化该类型,克隆它,创建它,破坏它,将其转换为另一种类型等 - 无论您想要什么。

下一步是一种通过均匀类型来存储该类型的方法,类似于boost::variant。简化(省略const方法,例如)示例您可以建立:

class Variant
{
public:
    virtual ~Variant() {}
    virtual int type() const = 0;
    virtual void* data() = 0;
    // Can/should use a smart pointer here (for ABI, make sure it captures
    // destruction at the call site).
    virtual Variant* clone() const = 0;
    template <class T>
    T& get()
    {
        assert(type_code<T>() != -1 && "Type is unknown!");
        assert(type() == type_code<T>() && "Mismatching types!");
        return static_cast<T*>(data());
    }
    template <class T>
    Variant& operator=(const T& new_val)
    {
        assert(type_code<T>() != -1 && "Type is unknown!");
        assert(type() == type_code<T>() && "Mismatching types!");
        *static_cast<T*>(data()) = new_val;
    }
    // ...
};
template <class T>
class VariantT: public Variant
{
public:
    explicit VariantT(const T& ival): val(ival), code(type_code<T>()) 
    {
        assert(code != -1 && "Type is unknown!");
    }
    virtual VariantT* clone() const override {return new VariantT(*this);}
    virtual int type() const override {return type_code<T>();}
    virtual void* data() override {return &val;}
private:
    T val;
};

现在,您可以存储您的原始类型,甚至可以存储Variantt内部的字段,其高度在Variantt等中,并且可以通过Variant*参考它们。示例:

VariantT<double> var_double(1.5);
Variant& var = var_double;
double my_double = var.get<double>(); // --> 1.5
int my_int = var.get<int>(); // assertion failure -- type mismatch.
unique_ptr<Variant> clone(var.clone()); // make a copy

这里有一些vptr的开销,但是如果您需要这种可扩展的属性设计,则比仅在汇总对象级别应用这些抽象要少得多的努力。如果您需要更多的安全性,则还可以将这些仅调试的断言变成具有运行时分支的异常或错误处理程序,如果您可以支付负担得起的周期。使用此功能,您可以提供具有反射的对象(可用的列表变体),通过变体统一存储其属性*,将序列化映射到适当的类型代码,并均匀地序列化特定属性/属性的整个对象,等等。

<</p> <</p> <</p>
相关文章: