C++ C++;类特定属性或外部结构的虚拟方法

C++ C++;类特定属性或外部结构的虚拟方法,c++,attributes,virtual,getter,C++,Attributes,Virtual,Getter,我有一组类,它们都是从一个公共基类派生的。我想以多态方式使用这些类。接口定义了一组getter方法,这些方法的返回值在给定的派生类中是常量,但在不同的派生类中有所不同。e、 g: enum AVal { A_VAL_ONE, A_VAL_TWO, A_VAL_THREE }; enum BVal { B_VAL_ONE, B_VAL_TWO, B_VAL_THREE }; class Base { //... virtual AVal getAVal() co

我有一组类,它们都是从一个公共基类派生的。我想以多态方式使用这些类。接口定义了一组getter方法,这些方法的返回值在给定的派生类中是常量,但在不同的派生类中有所不同。e、 g:

enum AVal
{
  A_VAL_ONE,
  A_VAL_TWO,
  A_VAL_THREE
};

enum BVal
{
  B_VAL_ONE,
  B_VAL_TWO,
  B_VAL_THREE
};

class Base
{
  //...
  virtual AVal getAVal() const = 0;
  virtual BVal getBVal() const = 0;
  //...
};

class One : public Base
{
  //...
  AVal getAVal() const { return A_VAL_ONE };
  BVal getBVal() const { return B_VAL_ONE };
  //...
};

class Two : public Base
{
  //...
  AVal getAVal() const { return A_VAL_TWO };
  BVal getBVal() const { return B_VAL_TWO };
  //...
};
等等

这是一种常见的做事方式吗?如果性能是一个重要的考虑因素,我是否最好将属性拉到外部结构中,例如:

struct Vals
{
  AVal a_val;
  VBal b_val;
};
在每个实例中存储一个
VAL*
,并按如下方式重写
Base

class Base
{
  //...
  public:
    AVal getAVal() const { return _vals->a_val; };
    BVal getBVal() const { return _vals->b_val; };
  //...
  private:
    Vals* _vals;
};

额外的解引用本质上与vtable查找相同吗?这种情况的惯用语是什么?这两种解决方案都是愚蠢的吗?任何见解都是非常值得赞赏的

第一种方法似乎更清晰,并迫使您覆盖这些方法(无论如何,在第一个孩子时)。我认为虚拟呼叫的开销往往比人们预期的要小。只有当您分析代码并且虚拟调用占用大量时间时,我才会尝试像您的第二种方法那样进行优化


也就是说,你想解决什么问题?有时这样的类ID很有用,但有时不同的接口抽象可以完成相同的事情,而根本没有这样的接口。

我个人会实现一种GetTypeStats(),它返回一个(引用)结构,其中包含所有派生的特定信息,或者像在D3D中一样的查询界面。在这种情况下,还应该考虑静态多态性。但是,如果您的类必须是运行时多态的,那么您就无法真正消除虚拟函数调用。

如果所有不同之处都是值,并且它们在编译时是固定的,您可以将它们设置为模板参数:

template< AVal aval, BVal bval>
class Derived : public Base
{
  AVal getAVal() const { return aval };
  BVal getBVal() const { return bval };
};

typedef Derived<A_VAL_ONE, B_VAL_ONE> One;
typedef Derived<A_VAL_TWO, B_VAL_TWO> Two;
模板
派生类:公共基
{
AVal getAVal()常量{return AVal};
BVal getBVal()常量{return BVal};
};
typedef派生一个;
typedef派生两个;

这是穷人对多态类型执行
动态强制转换
的常用方法,程序员希望避免使用
动态强制转换
。在这些情况下,这是一个微观优化。与所有微观优化一样,在进行之前,您需要根据需要进行合理的判断。如果探查器告诉您这样做而不是
dynamic\u-cast
,没有任何性能提升,那么您最好只使用
dynamic\u-cast

设计以实现清晰性和易于扩展性。这两种方法都不会出现在探查器的雷达上,除非这是您最内部的程序操作。免责声明:本项目纯粹出于娱乐/探索/教育目的。实际的类层次结构是脚本类型原语/容器类的集合。被访问的属性由各种“类型”信息组成(因此类是常量,类集合是变量)。因为洗牌这些对象并执行这些getter是vm核心工作的一个重要部分,所以我想避免做一些不合理或明显低效的事情。哦,是的,谢谢你提出这个问题!当前的实现实际上使用了上面提到的外部结构方法,并提供了一个getter方法来直接获取对结构的const访问。您可以在基类中创建结构,并让派生类在构造函数中设置数据成员。如果我没有弄错的话,这种方法(在基类中创建结构)的问题是,每个实例将包含结构的一个副本。使用虚方法或指向外部结构的指针,许多实例可以共享一组类型信息。我误解你了吗?管理这些指针的成本远远超过复制结构的成本,尤其是当它只包含几个枚举值时。与恒定偏移量访问相比,取消对它的引用,再加上线程安全智能指针的开销,对于这样小的数据来说不是一个好主意。当前的实现(请不要责备我)不使用指向动态内存的智能指针。相反,每个结构的一个
extern const
实例在每个派生类的头文件中声明,并在相应的源文件中定义。这些结构的地址被传递给派生构造函数中的基类,并在基类中将其分配给
const struct*
。这很难看吗?我并不反对你,但我不确定
dynamic\u cast
如何替代我在这里介绍的内容。例如,我可能通过一个函数运行这些对象的列表,该函数的行为根据其中一个函数返回的值进行切换。您是否建议我尝试使用
dynamic\u cast
按顺序对派生类型进行强制转换,直到找到一个不返回
NULL
的强制转换,而不是打开getter值?(我是否完全误解了你的建议?)。事实上,有时不需要铸造。我还是误会吗?@acanaday:我不是说是误会。我想说的是,很多时候我看到这样的构造,它是一个穷人的
动态\u cast
尝试。我的帖子可能适合你,也可能不适合你。哦,好吧!谢谢你的洞察力!我只是想确保我没有遗漏什么。然而,这并不能避免虚拟覆盖的需要,而且它的可读性(IMHO)不如第一个示例中的显式虚拟覆盖。@acanaday:我猜sbi的帖子和我的一样,只是想给你一些额外的见解。别生气,我们只是