问题
I designed a series of related classes, and in order to be able to manage them I made them derive from a single abstract class.
These classes all need access to a series of shared resources, and I found myself creating a vector of pointers in each, all of them identical (they necessarily must be). It seems like making a static member in the base class would give all of the derived classes access to this vector, meaning I need only build it once (it's not going to change either after it's been built, just looked up).
My question is if this is ok, and if so, how can I then build it, without calling a 'fill the vector' method from one of the derived classes?
My thinking was to do something like
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;
};
Then when I instantiate an object of any class derived from AbstractClass, I'd have access to the lResource vector, which is what I want.
Would this work? Is it horrible? Is it ok?
回答1:
The better solution would be to just make an object with the vectors in and then only instantiate it once and give the other classes a pointer or reference to it. Static data should be absolutely avoided unless necessary and this just isn't necessary.
回答2:
You can add a static function to initialise your static vector:
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;
}
回答3:
It would work, where work = compile & run.
However, all child classes will be accessing the same static vector, which means there won't be a different copy of the static vector for each child class.
For a better explanation of what I mean read the following So thread:
Are static fields inherited?
SOLUTION:
One solution is to have your parent class a template class as follows:
template<T>
class Parent<T> {
public:
static std::vector<T> sharedResource_;
}
class ChildA : Parent<ChildA> {
}
class ChildB : Parent<ChildB> {
}
In the above code, you will get a shared resource for all instances of ChildA and another one shared between instances of ChildB.
Is it right?
Well, I think it is not considered good. One of the related discussions to this is in comments to the following SO question and also under my answer to the question:
How to do "static overloaded const" in C#?
回答4:
You could try boost::assign::list_of, something like this:
vector<Resource*> AbstractClass::lResource = list_of( &res0 )( &res1 );
回答5:
I have few points here.
- Your vectory probably having size of 0. This could lead to some crash. You will have to allocate it before using. You can give a static or global initialize.
- Do you really want a vector? Vector is appropriate when you're using some dynamic memory allocation. The enums are static. You can give a simple count and allocate it as an array.
- Do you really want a static member? Static member usually used while you're sharing it between the objects of the same class. Can you satisfy the requirement with an external objects which is local/global within the class? Also can you make static function out of the class?
回答6:
Since you are creataing the vector of "resource pointer" and not reserving the spaces for object in advance ,your sysetem might crash in future. Why? Vector create a block of memory when you insert element and uses the same block until it hits its capcity. Once it hits its capcality and you inset a new element, vector will allocate a new memory (twice as previous allocated memory) and copies all the existing elements into new memory. Since this is a vector of "pointers", it is going to invaliadate all the refernces.
回答7:
What I usually do in these cases is add a middle templated layer so I have a structure like this:
Define your abstract interface:
class A
{
public:
virtual ~A(){}
virtual void f() = 0
virtual A* Clone() const = 0
}
Put the resources commonly used by the child in a template and define the boiler-plate function using CRTP if necessary keeping the necessary interface function still abstract
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;
}
Finally the different concrete classes complete the implementation and do something special with those resources if necessary
class Child: public A_T<Child>
{
public:
void foo();
}
来源:https://stackoverflow.com/questions/6387029/can-i-have-static-data-members-in-an-abstract-class