我可以翻译。抽象类中是否可以有静态数据成员?

6

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

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

我的问题是如果这样做可以吗?如果可以,那么我该如何构建它,而不是从一个派生类中调用“填充向量”的方法?

我的想法是做一些像这样的事情

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向量,这正是我想要的。

这样做可行吗?很糟糕吗?还是可以的?


“会起作用吗?”嗯,你可以通过尝试来回答这个问题。它很糟糕吗?我不这么认为,我认为它还不错。 - GolezTrol
有多糟糕,取决于你对“抽象”定义的严格程度。有些人认为抽象基类应该只包含抽象函数,而其他人则不那么严格。 - Bo Persson
7个回答

1

这会起作用,其中工作=编译和运行。

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

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

静态字段是否继承?

解决方案:

一个解决方案是将您的父类设置为模板类,如下所示:

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

class ChildA : Parent<ChildA> {
}

class ChildB : Parent<ChildB> {
}

在上面的代码中,您将为所有ChildA实例获得一个共享资源,另一个共享资源用于ChildB实例之间。
“这样做是否正确?”
嗯,我认为这不是一个好的选择。关于这个问题的相关讨论可以在以下SO问题的评论和我对该问题的回答下找到: 如何在C#中进行“静态重载常量”?

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

但全局实例不会同样“静态”,也就是说:在线程上下文中也存在问题吗? - rubenvb
@rubenvb:他明确表示向量在填充后不会被更改。我认为这并不是什么大问题。 - Puppy
是的,好的,我只是在卖弄学问 :s - rubenvb
嗯,那应该可行。我不想创建比必要更多的类,这就是为什么我回避它的原因。我想我可以在类外实例化向量,并在基类中放置一个指针,然后在每个派生类中指向它。 - Kian

0

我这里有几个要点。

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

0

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


0
您可以添加一个静态函数来初始化您的静态向量:
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;
}

0
你可以尝试使用 boost::assign::list_of,就像这样:
vector<Resource*> AbstractClass::lResource = list_of( &res0 )( &res1 );

0
通常在这种情况下,我会添加一个中间的模板层,这样我的结构就像这样:
定义你的抽象接口:
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();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接