Запись данных полиморфного класса в файл? - PullRequest
4 голосов
/ 01 декабря 2011

Итак, у меня есть эти классы.Существует один базовый класс, но у него есть / будет много и много производных, и эти производные классы также смогут иметь производные.Мне бы хотелось иметь функцию, которая записывает их двоичные данные в файл, но я не уверен, как это сделать с большим количеством производных классов.

Я думал о чем-тостроки:

void writeData(ofstream & _fstream)
{
    _fstream.write()//etc..
}

Но тогда каждый производный класс, который реализовал этот метод, должен будет записать все данные своего родительского класса, и это будет дублировать большой объем кода.

Что такоелучший способ сделать это без переписывания всего ранее написанного writeData() кода?

Ответы [ 4 ]

9 голосов
/ 01 декабря 2011

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

void Derived::writeData(ofstream & _fstream)
{
    // Base class writes its data
    Base::writeData(_fstream);

    // now I can write the data that is specific to this Derived class
    _fstream.write()//etc..
}
4 голосов
/ 01 декабря 2011

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

1 голос
/ 01 декабря 2011

Если вы хотите избежать перепроектирования всех реализаций функций производного класса для функций сериализации, вы можете пойти в другом направлении, от базового к производным классам:

В вашем базовом классе предусмотрена функция, отличная от virtual, для запуска процесса сериализации. Код клиента вызывает эту функцию через указатель (или ссылку). Также предоставьте виртуальную функцию, которая выполняет сериализацию для подкласса. Вызовите эту функцию из функции базового класса 'Serialize.

(РЕДАКТИРОВАТЬ) Если вы хотите предоставить функциональность по умолчанию для сериализации подклассов, но при этом хотите иметь возможность предоставлять специализированные функции для конкретных случаев, то функция, которая сериализует подклассы, не обязательно должна быть чисто виртуальной. Однако, когда я прочитал ваш OP, мне показалось, что каждый подкласс должен быть необходим для обеспечения этой функциональности. Чтобы смоделировать это требование, я сделал здесь функцию DoSerialize чисто виртуальной.

Пример:

class Base
{
public:
  void Serialize() const;
  virtual void DoSerialize() = 0;
};

class Derived : public Base
{
public:
  void DoSerialize() { /* MAGIC HAPPENS */ };
};

void Base::Serialize() const
{
  /* .. do serialization of base class here, or at the end -- whichever is appropriate .. */

  this->DoSerialize();  // serialize the derived class
}

/* ... */

Base* GetObject()
{
 /* ... */
}

int main()
{
  Base* obj = GetObject();
  obj->Serialize();
}
0 голосов
/ 01 декабря 2011

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

Посмотрите на это так - выполняемая здесь функция - сериализация и десериализация. Критическая вещь здесь - то, что это должно быть выполнено правильно. Следовательно, единственный класс, который может это сделать, - это тот, кто обладает полным знанием. Другими словами, это ваш производный класс.

Итак, бывают случаи, когда вам придется вызывать Base :: writeData (), но независимо от того, делаете ли вы это или нет, должно быть полностью оставлено на усмотрение производного класса. Помните, что вы хотите, чтобы ваша иерархия классов удовлетворяла некоторым базовым принципам проектирования . Как только вы это получите, это должно быть относительно просто.

...