Если подытожить, что люди здесь говорят, json_decode / encode кажется быстрее, чем сериализация / десериализация, НО Если вы сделаете var_dump, тип сериализованного объекта будет изменен. Если по какой-то причине вы хотите сохранить тип, переходите к serialize!
(попробуйте, например, stdClass vs array)
serialize / unserialize:
Array cache:
array (size=2)
'a' => string '1' (length=1)
'b' => int 2
Object cache:
object(stdClass)[8]
public 'field1' => int 123
This cache:
object(Controller\Test)[8]
protected 'view' =>
json encode / decode
Array cache:
object(stdClass)[7]
public 'a' => string '1' (length=1)
public 'b' => int 2
Object cache:
object(stdClass)[8]
public 'field1' => int 123
This cache:
object(stdClass)[8]
Как вы можете видеть, json_encode / decode преобразует все в stdClass, что не очень хорошо, информация об объекте теряется ... Так что решайте исходя из потребностей, особенно если это не только массивы. ..
Основная проблема с добавлением пост-конструкторов в C ++ заключается в том, что еще никто не установил, как обращаться с конструкторами пост-пост, пост-пост-постконструкторами и т. Д.
Основная теория состоит в том, что у объектов есть инварианты. Этот инвариант устанавливается конструктором. Как только он будет установлен, можно вызывать методы этого класса. С введением проектов, которые потребовали бы пост-конструкторов, вы вводите ситуации, в которых инварианты классов не устанавливаются после запуска конструктора. Следовательно, было бы столь же небезопасно разрешать вызовы виртуальных функций из постконструкторов, и вы сразу теряете одно очевидное преимущество, которое они, казалось, имели.
Как показывает ваш пример (возможно, вы не понимаете), они не нужны :
MyObject * obj = new MyObject;
obj->Initialize(); // virtual method call, required after ctor for (obj) to run properly
obj->AboutToDelete(); // virtual method call, required before dtor for (obj) to clean up properly
delete obj;
Пусть ' s показывают , почему эти методы не нужны. Эти два вызова могут вызывать виртуальные функции из MyObject
или одной из его баз. Однако MyObject :: MyObject ()
также может безопасно вызывать эти функции. После возврата MyObject :: MyObject ()
ничего не происходит, что сделало бы obj-> Initialize ()
безопасным. Таким образом, либо obj-> Initialize ()
неверен, либо его вызов может быть перемещен в MyObject :: MyObject ()
. Та же самая логика применяется в обратном порядке к obj-> AboutToDelete ()
. Самый производный деструктор будет запущен первым, и он по-прежнему может вызывать все виртуальные функции, включая AboutToDelete ()
.
MyObject :: MyObject ()
также может безопасно вызывать эти функции. После возврата MyObject :: MyObject ()
ничего не произойдет, что сделало бы obj-> Initialize ()
безопасным. Таким образом, либо obj-> Initialize ()
неверен, либо его вызов может быть перемещен в MyObject :: MyObject ()
. Та же самая логика применяется в обратном порядке к obj-> AboutToDelete ()
. Самый производный деструктор будет запущен первым, и он по-прежнему может вызывать все виртуальные функции, включая AboutToDelete ()
. MyObject :: MyObject ()
также может безопасно вызывать эти функции. После возврата MyObject :: MyObject ()
ничего не произойдет, что сделало бы obj-> Initialize ()
безопасным. Таким образом, либо obj-> Initialize ()
неверен, либо его вызов может быть перемещен в MyObject :: MyObject ()
. Та же самая логика применяется в обратном порядке к obj-> AboutToDelete ()
. Самый производный деструктор будет запущен первым, и он все еще может вызывать все виртуальные функции, включая AboutToDelete ()
. Initialize () неверна или ее вызов может быть перемещен в MyObject :: MyObject ()
. Та же самая логика применяется в обратном порядке к obj-> AboutToDelete ()
. Самый производный деструктор будет запущен первым, и он все еще может вызывать все виртуальные функции, включая AboutToDelete ()
. Initialize () неверна, или ее вызов может быть перемещен в MyObject :: MyObject ()
. Та же самая логика применяется в обратном порядке к obj-> AboutToDelete ()
. Самый производный деструктор будет запущен первым, и он по-прежнему может вызывать все виртуальные функции, включая AboutToDelete ()
. Хотя автоматизированного способа не существует, вы можете заставить пользователей передать данные, запретив им доступ к деструктору этого типа и объявив специальный метод удаления. В этом методе вы можете делать виртуальные вызовы, которые хотите. Создание может использовать тот же подход, что и статический фабричный метод.
class MyObject {
...
public:
static MyObject* Create() {
MyObject* pObject = new MyObject();
pObject->Initialize();
return pObject;
}
Delete() {
this->AboutToDelete();
delete this;
}
private:
MyObject() { ... }
virtual ~MyObject() { ... }
};
Теперь невозможно вызвать "удалить объект;" если сайт вызова не имеет доступа к закрытым членам MyObject.
Лучшее, что я могу придумать, - это реализовать ваш собственный интеллектуальный указатель с помощью статического метода Create, который обновляет экземпляр и вызывает Initialize, а в его деструкторе вызывает AboutToDelete и затем delete.
Я использовал очень тщательно разработанный фабричный метод Create ()
(статический член каждого класса) для вызова пары конструктор и инициализатор в том же порядке, в котором C # инициализирует типы. Он вернул shared_ptr
экземпляру типа, гарантируя выделение кучи. Со временем он оказался надежным и непротиворечивым.
Уловка: я сгенерировал свои объявления классов C ++ из XML ...
За исключением JavedPar's Идея метода предварительного разрушения, не существует готового решения, позволяющего легко выполнить двухэтапное построение / разрушение в C ++. Самый очевидный способ сделать это - следовать наиболее распространенному ответу на проблемы в C ++: «Добавьте еще один уровень косвенности». Вы можете заключить объекты этой иерархии классов в другой объект. Затем конструкторы / деструкторы этого объекта могут вызывать эти методы. Посмотрите, например, на идиому Couplien с конвертами букв или воспользуйтесь уже предложенным подходом с умным указателем.
http://www.research.att.com/~bs/wrapper.pdf Эта статья от Страуструпа решит вашу проблему.
Я тестировал это в VS 2008 и на UBUNTU против компилятора g ++. Он работал нормально.
#include <iostream>
using namespace std;
template<class T>
class Wrap
{
typedef int (T::*Method)();
T* p;
Method _m;
public:
Wrap(T*pp, Method m): p(pp), _m(m) { (p->*_m)(); }
~Wrap() { delete p; }
};
class X
{
public:
typedef int (*Method)();
virtual int suffix()
{
cout << "X::suffix\n";
return 1;
}
virtual void prefix()
{
cout << "X::prefix\n";
}
X() { cout << "X created\n"; }
virtual ~X() { prefix(); cout << "X destroyed\n"; }
};
class Y : public X
{
public:
Y() : X() { cout << "Y created\n"; }
~Y() { prefix(); cout << "Y destroyed\n"; }
void prefix()
{
cout << "Y::prefix\n";
}
int suffix()
{
cout << "Y::suffix\n";
return 1;
}
};
int main()
{
Wrap<X> xx(new X, &X::suffix);
Wrap<X>yy(new Y, &X::suffix);
}
Еще не видел ответа, но базовые классы - это только один способ добавить код в иерархию классов. Вы также можете создавать классы, предназначенные для добавления на другую сторону иерархии:
template<typename Base>
class Derived : public Base {
// You'd need C++0x to solve the forwarding problem correctly.
Derived() : Base() {
Initialize();
}
template<typename T>
Derived(T const& t): Base(t) {
Initialize();
}
//etc
private:
Initialize();
};