具有一般和专业属性的课程
Class with general and specialized attributes
如何基于类型对一类建模类别和特定属性。例如,我有一个原始类。原始类具有以下一般成员:原型,翻译,旋转,以及基于原始类型的其他字段。
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
的开销,但是如果您需要这种可扩展的属性设计,则比仅在汇总对象级别应用这些抽象要少得多的努力。如果您需要更多的安全性,则还可以将这些仅调试的断言变成具有运行时分支的异常或错误处理程序,如果您可以支付负担得起的周期。使用此功能,您可以提供具有反射的对象(可用的列表变体),通过变体统一存储其属性*,将序列化映射到适当的类型代码,并均匀地序列化特定属性/属性的整个对象,等等。
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- C++调用具有 *this 属性的单个帮助程序函数
- 编写了一个C++代码来检查表达式是否具有平衡括号并且我的代码未运行.我已经卡了一天了
- 具有相同特征的两个对象是否只在内存中存储一次?无论定义它们的函数是什么,都是不同的
- C++有没有办法强制重写一组方法,如果其中一个方法在子类中具有重写?
- 具有常量属性的不可变类
- 如何在不知道属性具有哪些构造函数的情况下初始化属性?
- 一种优雅或至少可行的方法,用于使用和接受具有重载方法和运算符的不同大小的文字数组常量
- 循环中的变量被设置为下一个数组的元素始终具有相同的内存地址?
- 类对象属性是否可以调用返回属性应具有的值的方法C++?
- 有没有一种方法可以创建具有广义属性的命名空间
- 如何查找具有一组整数的函数的'max absolute sum'
- 哪些 gnu 属性具有 c++11 语法
- 查找对象向量中属性具有相同值的对象
- 迭代向量中属性具有特定值的元素范围
- 我如何拥有一个在 c++ 中具有一组坐标的数组
- 包括具有一个头文件和独立源文件的特定于平台的库
- 每次需要其中一个类的实例时,是否具有一组类的额外副本或从文件中读取更多内存
- 如何在 c++ 中输出指针对象的属性(具有 2 个或更多属性)