我可以在抽象类中拥有静态数据成员吗

Can I have static data members in an abstract class?

本文关键字:静态 数据成员 拥有 抽象类 我可以      更新时间:2023-10-16

我设计了一系列相关的类,为了能够管理它们,我让它们从一个抽象类派生。

这些类都需要访问一系列共享资源,我发现自己在每个类中创建了一个指针向量,所有的指针都是相同的(它们必须是)。似乎在基类中创建一个静态成员会让所有派生类都可以访问这个向量,这意味着我只需要构建一次它(在构建后也不会改变,只是查找一下)。

我的问题是,这是否可以,如果可以,我如何构建它,而不从其中一个派生类调用"填充向量"方法?

我的想法是做一些类似的事情

class Resource {};
enumR {RES0, RES1};
class AbstractClass
{
    public:
        virtual void OnInit() = 0;
        void static fillVector(Resource* pResource, enumR Resourcename)
            {lResource[Resourcename]=pResource;};
    protected:
        static vector<Resource*> lResource;
};
vector<Resource*> AbstractClass::lResource;
int main()
{
    Resource res0, res1;
    AbstractClass::fillVector(&res0, RES0);
    AbstractClass::fillVector(&res1, RES1);
    return 0;
};

然后,当我实例化从AbstractClass派生的任何类的对象时,我都可以访问lResource向量,这正是我想要的。

这行得通吗?太可怕了吗?可以吗?

它会起作用,其中work=compile&跑

然而,所有子类都将访问相同的静态向量,这意味着每个子类不会有不同的静态向量副本。

为了更好地解释我的意思,请阅读以下So线程:

静态字段是继承的吗?

解决方案:

一个解决方案是让你的父类有一个模板类,如下所示:

template<T>
class Parent<T> {
    public:
        static std::vector<T> sharedResource_;
}
class ChildA : Parent<ChildA> {
}
class ChildB : Parent<ChildB> {
}

在上面的代码中,您将获得ChildA的所有实例的共享资源,以及ChildB的示例之间共享的另一个资源。

对吗

嗯,我认为这不太好。与此相关的讨论之一是对以下SO问题的评论,也是在我对该问题的回答下:

如何做";静态过载常量";在C#中?

更好的解决方案是只创建一个包含向量的对象,然后只实例化一次,并给其他类一个指向它的指针或引用。除非必要,否则应该绝对避免静态数据,而这根本没有必要。

您可以添加一个静态函数来初始化您的静态向量:

class AbstractClass
{
    private:
        // Add this
        static vector<Resource*> CreateResources();
    protected:
        static vector<Resource*> lResource;
};
vector<Resource*> AbstractClass::lResource = CreateResources();
vector<Resource*> AbstractClass::CreateResources()
{
    vector<Resource*> resources;
    resources[RES0] = new Resource();
    resources[RES1] = new Resource();
    return resources;
}

您可以尝试boost::assign::list_of,类似这样的东西:

vector<Resource*> AbstractClass::lResource = list_of( &res0 )( &res1 );

我在这里有几点。

  • 您的向量大小可能为0。这可能会导致一些崩溃。在使用之前,您必须对其进行分配。您可以进行静态初始化或全局初始化
  • 你真的想要一个向量吗?当您使用一些动态内存分配时,Vector是合适的。枚举是静态的。您可以给出一个简单的计数,并将其分配为一个数组
  • 你真的想要一个静态成员吗?静态成员通常在同一类的对象之间共享时使用。你能用类中的局部/全局外部对象来满足这个要求吗?你还可以把静态函数从类中提取出来吗

由于您正在创建"资源指针"的向量,并且没有预先为对象保留空间,因此您的系统可能在将来崩溃。为什么?Vector在插入元素时创建一个内存块,并使用相同的块直到达到其capcity。一旦达到其capcality并插入一个新元素,vector将分配一个新内存(是以前分配内存的两倍),并将所有现有元素复制到新内存中。由于这是一个"指针"的向量,它将使所有引用无效。

在这些情况下,我通常会添加一个中间模板层,这样我就有了这样的结构:

定义你的抽象界面:

class A
{
public:
virtual ~A(){}
virtual void f() = 0 
virtual A* Clone() const = 0
}

将孩子常用的资源放在模板中,必要时使用CRTP定义锅炉板功能,保持必要的接口功能仍然抽象

template<class Derived>
class A_T: public A
{
public:
virtual void f() = 0;
virtual A* Clone const
{
return new Derived(dyn_cast<Derived&>(*this))
}
void ManageRes();
private:
vector myResource;
}

最后,不同的具体类完成了实现,并在必要时使用这些资源做一些特殊的事情

class Child: public A_T<Child>
{
public: 
void foo();
}