Как полиморфно инициализировать статический элемент

Скажем, у меня есть базовый класс Validator.

class Validator
{
public:
  void validate(const string& str)
  {
    if( k_valid_keys.find(str) == k_valid_keys.end() ) 
      throw exception();
  }
private:
  const static std::set<string> k_valid_keys;
};

Теперь предположим, что мне нужно расширить класс Validator. Каждый производный класс будет иметь собственный набор действительных ключей.
Моя цель:

  1. оставить k_valid_keys членом Validator. Нет необходимости добавлять его в каждый производный класс, особенно если их несколько.
  2. сохранить k_valid_keys static. Предположим, у меня есть несколько экземпляров Validator (и его производных классов), а инициализация k_valid_keys требует больших затрат.

Как я могу полиморфно инициализировать член static? ну, я знаю, что это невозможно сделать (пожалуйста, поправьте, если я ошибаюсь).

Итак, предполагая, что это невозможно сделать, есть идеи по лучшему дизайну для этой проблемы?


person idanshmu    schedule 26.03.2014    source источник
comment
Вы говорите, что каждый производный класс будет иметь свой собственный набор действительных ключей, поэтому будет ли каждый производный класс иметь свой собственный статический набор действительных ключей?   -  person Nicolas Louis Guillemot    schedule 26.03.2014
comment
это то, чего я пытаюсь избежать. зачем добавлять static к каждому производному классу, если я могу волшебным образом инициализировать его виртуально.   -  person idanshmu    schedule 26.03.2014
comment
У вас может быть унаследованная виртуальная функция со статической переменной внутри нее.   -  person Nicolas Louis Guillemot    schedule 26.03.2014
comment
Опять же, это не помогает мне избежать k_valid_keys в каждом производном классе.   -  person idanshmu    schedule 26.03.2014
comment
Это не обязательно должна быть переменная-член, и вы унаследуете проверку родительского класса, если не переопределите ее.   -  person Nicolas Louis Guillemot    schedule 26.03.2014
comment
возможно, мы не на той же странице. Буду признателен, если вы опубликуете ответ с вашим предложением.   -  person idanshmu    schedule 26.03.2014


Ответы (3)


Поскольку k_valid_keys объявлен static в Validator, все производные классы от Validator будут совместно использовать один и тот же экземпляр k_valid_keys. Вот и все, вы не сможете иметь более одного экземпляра подкласса Validator одновременно в своей программе, иначе ваши разные экземпляры подклассов Validator добавят элементы в одну и ту же структуру.

То есть статическая переменная-член класса — это просто глобальная переменная всей вашей программы.

Если у вас есть два или более подкласса Validator, но вы гарантируете, что у вас будет только один экземпляр, вы просто инициализируете k_valid_keys в конструкторе подкласса.

person vz0    schedule 26.03.2014
comment
Ты прав. спасибо за разъяснение этого. Итак, я предполагаю, что то, о чем я прошу, невыполнимо? - person idanshmu; 26.03.2014
comment
@idanshmu IMHO Думаю, слишком много ограничений. Зачем вам нужен статический k_valid_keys? Производительность? - person vz0; 26.03.2014
comment
потому что он статичен по своей природе. он не должен быть привязан к экземпляру, поскольку он является константой для класса Validator. Я не понял, что мои ограничения не имеют смысла. - person idanshmu; 26.03.2014
comment
@idanshmu Как насчет перемещения статического поля k_valid_keys в каждый подкласс? - person vz0; 26.03.2014
comment
Вот что я должен сделать. Я пытался избежать этого, потому что не понимал, что у меня не может быть нескольких определений для static члена (как вы правильно сказали). Я пытался сохранить подкласс как можно более чистым, но это невозможно сделать таким образом. - person idanshmu; 26.03.2014

Вы можете сделать следующее: вместо одного набора ключей в качестве статического члена используйте карту сопоставления std::type_index с набором ключей (или, если вы не можете использовать C++11, std::type_info*). В каждом из ваших производных классов есть виртуальная функция, которая возвращает набор действительных_ключей для класса, а функция validate в базовом классе должна получить с typeid type_info фактического объекта, проверьте, есть ли у него уже ключи на карте - если нет, вызывается виртуальная функция, возвращающая набор, и запись добавляется на карту.

person Wojtek Surowka    schedule 26.03.2014
comment
это не помогает мне избежать k_valid_keys в каждом производном классе. - person idanshmu; 26.03.2014
comment
Да, это так. Карта, которую я предлагаю, является статическим членом базового класса. Единственное, что нужно добавить в производные классы, — это виртуальную функцию, возвращающую ключи, и каждая такая функция будет вызываться только один раз. - person Wojtek Surowka; 26.03.2014
comment
ХОРОШО. теперь я вижу, к чему ты клонишь. кажется правильным. - person idanshmu; 26.03.2014
comment
Для этого существует стандартное средство, поскольку type_info* не гарантируется выполнение правильная вещь. - person Potatoswatter; 26.03.2014
comment
Хотя здесь можно было бы использовать type_index, я вообще не вижу необходимости в rtti. - person rubenvb; 26.03.2014
comment
Что вы предлагаете без RTTI? - person Wojtek Surowka; 26.03.2014

Передайте ссылку на k_valid_keys в конструкторе ваших классов Validator и инициализируйте ссылку на член. Вы пропустите построение для нескольких классов Validator, но вам придется управлять его временем жизни.

Затем вы можете иметь по одному для каждого унаследованного типа, если хотите или нет.

Использование регистра k_valid_keys, доступ к которому осуществляется по типу или ключу, также может работать. Конечно, вам нужно будет передать ссылку на этот регистр вашим Validator классам.

person Eric Fortin    schedule 26.03.2014