【问题标题】:C++: Enforce definition of a static memberC++:强制定义静态成员
【发布时间】:2014-06-11 01:39:27
【问题描述】:

我有不同的Components集合,其中每个Component子类化一个抽象类IComponentIComponent定义了一个纯虚函数virtual ID_TYPE getId() = 0;,所以每个组件都需要为它创建一个实现。

考虑到每个组件只能添加一次,所以它的 ID 对所有实例和集合函数都相等

IComponent* ICollection::getComponent(const ID_TYPE);

我想要一个额外的 static 方法,就像上面描述的那样,以便在不需要创建实例(可能没有默认构造函数)的情况下检索组件的 ID像

collection1.getComponent(MyComponentA::getId())->something();
collection2.getComponent(MyComponentA::getId())->something();

我知道没有虚拟静态成员之类的东西,静态方法不能被覆盖。但是是否有其他方法可以确保IComponent 的每个子类都定义了这样的静态方法?

【问题讨论】:

  • anything 怎么知道不存在的ComponentID(它还没有被创建)?
  • 如果你调用它并且它不存在,你会得到一个编译错误,所以我不太明白问题是什么。 (而且它是“覆盖”,而不是“覆盖”,因为动词是“覆盖”。)
  • @PaulEvans ID 是静态的,每个组件都是唯一的
  • 在这种情况下可能可以使用C++ traits concept
  • 你可以通过创建多种方法来做你想做的事:stackoverflow.com/a/1820676/1098041 不过我不确定这是一个好习惯。

标签: c++


【解决方案1】:

所以我会选择这样的东西:

ComponentBase.h:

template <typename T>
class ComponentBase {
   ....
   .... 
protected:
   ComponentBase() { (void)getClassId(); }
public:
   static int getClassId();
   ....
};

组件1.h:

#include "ComponentBase.h"

class Component1: public ComponentBase<Component1> {
public:
    Component1(....) {}
    ....
};

组件1.cc:

#include "Component1.h"

....

template <>
int ComponentBase<Component1>::getClassId() {
    return 1;
}

如果开发人员忘记为类ComponentX 定义ComponentBase&lt;ComponentX&gt;::getClass(),项目将不会链接。

实际上,我不会将 ID 的选择权留给组件开发人员。这种技术允许提供一个仅基于ComponentX 类名的通用实现,从而“免费”获得 ID 的唯一性。

【讨论】:

    【解决方案2】:

    一种方法是制作一些模板魔法,以防您可以修改IComponent 接口和您的类。比如:

    #include <iostream>
    
    using namespace std;
    typedef int ID_TYPE;
    
    class IComponent
    {
    public:
        IComponent() {}
    
        template <class T>
        ID_TYPE gclassId()
        {
            return T::classId(); 
    
        }
    
        virtual ID_TYPE getId() = 0;
    };
    
    class Comp1 : public IComponent
    {
    public:
        Comp1() {}
        virtual ID_TYPE getId() {return IComponent::gclassId<Comp1>();}
        static ID_TYPE classId() {return 1; }
    };
    
    class Comp2 : public IComponent
    {
    public:
        Comp2() {}
        virtual ID_TYPE getId() {return IComponent::gclassId<Comp2>(); }
        static ID_TYPE classId() {return 2;}
    };
    
        /*
    class Comp3 : public IComponent
    {
    public:
        Comp3() {}
        virtual ID_TYPE getId() {return IComponent::gclassId<Comp3>(); }
    };
        */
    
    int main()
    {
        Comp1 a;
        Comp2 b;
        IComponent* t = new Comp2();
        std::cout << a.getId() << t->getId();
        delete t;
        return 0;
    }
    

    这要求您每个IComponent 派生类声明一个静态成员classId()。如果你取消注释Comp3,你会得到一个编译错误。

    通过修改它是指您可以访问源代码。请忽略您的 ID_TYPE 的 typedef,它可以是您想要的任何类型,只要您的虚函数通过 gclassIdIComponent 返回真实 ID,而后者又从类。

    【讨论】:

    • 这还不错。正如fritzone所说,它至少强制定义静态。它仍然不会强制派生类使用它,并且 IComponent 将不再是纯接口,因为它包含一个实现。我不确定这是否值得我增加复杂性,但它很有创意。
    • @brader24 是的,没错,它并没有强制使用它,但它给出了如何使用它的明确指南,而实际使用它取决于实现组件的程序员。跨度>
    【解决方案3】:

    我不知道有什么方法可以强制派生类实现成员,除非通过纯虚方法。

    我建议简单地使用纯虚拟或类似的文档来指示 ID 对于类实现而不是类实例应该是唯一的。在理想情况下,您应该能够指望派生类的开发人员阅读方法的文档,以了解它需要返回静态标识符而不是实例标识符。无论如何,您必须依靠它们来正确实现其他纯虚方法。

    【讨论】:

      猜你喜欢
      • 2011-04-01
      • 2021-09-11
      • 1970-01-01
      • 1970-01-01
      • 2011-03-30
      • 2012-07-05
      • 2011-09-19
      • 2017-10-03
      相关资源
      最近更新 更多