Могу ли я иметь статические элементы данных в абстрактном классе?

Я разработал серию связанных классов и, чтобы иметь возможность управлять ими, сделал их производными от одного абстрактного класса.

Всем этим классам нужен доступ к ряду общих ресурсов, и я обнаружил, что создаю вектор указателей в каждом, все они идентичны (они обязательно должны быть). Похоже, что создание статического члена в базовом классе предоставит всем производным классам доступ к этому вектору, что означает, что мне нужно построить его только один раз (он не изменится ни после того, как он был построен, просто посмотрел).

У меня вопрос, если это нормально, и если да, то как я могу его построить, не вызывая метод «заполнить вектор» из одного из производных классов?

Я думал сделать что-то вроде

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, чего я и хочу.

Это сработает? Это ужасно? Это нормально?


person Kian    schedule 17.06.2011    source источник
comment
Сработает ли это? .. Что ж, вы можете ответить на этот вопрос, просто попробовав. Это ужасно? Я так не думаю, я думаю, что это нормально.   -  person GolezTrol    schedule 17.06.2011
comment
Насколько это ужасно, зависит от того, насколько строго вы определяете абстрактное. Некоторые люди считают, что абстрактный базовый класс должен содержать только абстрактные функции. Другие менее строги.   -  person Bo Persson    schedule 17.06.2011


Ответы (7)


Лучшим решением было бы просто создать объект с векторами, а затем только один раз создать его экземпляр и дать другим классам указатель или ссылку на него. Статических данных следует избегать без необходимости, и в этом нет необходимости.

person Puppy    schedule 17.06.2011
comment
Но не будет ли глобальный экземпляр одинаково статичным, т. Е. Проблемным? Я думаю о static == проблематике в контексте потоковой передачи ... - person rubenvb; 17.06.2011
comment
@rubenvb: он прямо заявляет, что вектор никогда не изменяется после заполнения. Я думаю, что это не такая уж большая проблема. - person Puppy; 17.06.2011
comment
да, хорошо, я просто задница педантиса :s - person rubenvb; 17.06.2011
comment
Хм, это сработает. Я не хотел проводить больше занятий, чем необходимо, поэтому и уклонялся от этого. Думаю, я мог бы создать экземпляр вектора вне класса и поместить указатель в базовый класс, на который я затем указываю в каждом производном классе. - person Kian; 18.06.2011

Это будет работать, где работа = компиляция и запуск.

Однако все дочерние классы будут обращаться к одному и тому же статическому вектору, что означает, что не будет другой копии статического вектора для каждого дочернего класса.

Чтобы лучше понять, что я имею в виду, прочтите следующую ветку So:

Наследуются ли статические поля?

РЕШЕНИЕ:

Одно из решений - сделать родительский класс классом шаблона следующим образом:

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

class ChildA : Parent<ChildA> {
}

class ChildB : Parent<ChildB> {
}

В приведенном выше коде вы получите общий ресурс для всех экземпляров ChildA и еще один общий ресурс для экземпляров ChildB.

Это правильно?

Что ж, думаю, это не считается хорошим. Одно из связанных с этим обсуждений находится в комментариях к следующему вопросу SO, а также под моим ответом на вопрос:

Как сделать статическую перегруженную константу в C #?

person Ozair Kafray    schedule 17.06.2011

Вы можете добавить статическую функцию для инициализации статического вектора:

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;
}
person DanDan    schedule 17.06.2011

Вы можете попробовать boost :: assign :: list_of, примерно так:

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

У меня здесь несколько моментов.

  • Вероятно, ваш вектор имеет размер 0. Это может привести к сбою. Вам нужно будет выделить его перед использованием. Вы можете выполнить статическую или глобальную инициализацию.
  • Вы действительно хотите вектор? Вектор уместен, когда вы используете некоторое динамическое распределение памяти. Перечисления статичны. Вы можете просто подсчитать и разместить его в виде массива.
  • Вы действительно хотите статический член? Статический член обычно используется, когда вы делитесь им между объектами одного класса. Можете ли вы удовлетворить требование с помощью внешних объектов, которые являются локальными / глобальными внутри класса? Также можете ли вы сделать статическую функцию из класса?
person sarat    schedule 17.06.2011

Поскольку вы создаете вектор «указателя ресурса» и заранее не резервируете места для объекта, ваша система может выйти из строя в будущем. Почему? Vector создает блок памяти, когда вы вставляете элемент, и использует тот же блок, пока не достигнет своей емкости. Как только он достигает своей емкости и вы вставляете новый элемент, вектор выделяет новую память (в два раза больше, чем ранее выделенная память) и копирует все существующие элементы в новую память. Так как это вектор «указателей», он будет инвалифицировать все ссылки.

person Alok    schedule 17.06.2011

В таких случаях я обычно добавляю средний шаблонный слой, поэтому у меня получается такая структура:

Определите свой абстрактный интерфейс:

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();
}
person Triskeldeian    schedule 16.03.2015