Est-ce un mauvais bidouillage? memcpy avec des classes virtuelles

Ok, voici quelques trucs que j’ai imaginés, mais j’ai des problèmes à les utiliser dans du code réel. Ceci est un exemple de travail de ce que je veux faire

class VirtualParent { public: virtual void printVal() = 0; }; class Parent : public VirtualParent { public: virtual void printVal() { cout << "Val is: " << val << endl; } void SetVal(foo * v) { val = v; } protected: foo* val; }; class Child : public Parent { public: virtual void printVal() { cout <print(); } }; int _tmain(int argc, _TCHAR* argv[]) { Parent * p_ptr = new Child; foo * val = new foo; p_ptr->SetVal(val); p_ptr->printVal(); for(int n = 0;n printVal(); } return 0; } 

Cet exemple fonctionne si j’utilise memcpy ou memcpy_s. L’idée est de passer une classe dérivée utilisateur à une fonction, qui créera alors plusieurs copies, mais comme je ne connais pas le type de classe dérivée à la compilation, j’y ai pensé. Comme je l’ai dit, cela fonctionne parfaitement et je l’ai copié dans mon moteur, où je veux l’utiliser, et des problèmes de mémoire surgissent de nulle part, et ils semblent être relus à ce hack. L’utilisation de memcpy_s en résout certains. Est-ce quelque chose de «bon» à faire ou y a-t-il un meilleur moyen?

Voici le code du “monde réel”

 _Lua::ScriptedEntity * newScript = EntityBase;//nullptr; //assert(HeapValidate(GetProcessHeap(),0,nullptr)); //memcpy( &newScript, &EntityBase, sizeof(_Lua::ScriptedEntity) ); memcpy_s(&newScript, sizeof(EntityBase), &EntityBase, sizeof(EntityBase)); //assert(HeapValidate(GetProcessHeap(),0,nullptr)); ssortingng luaPath = transforms.next_sibling().next_sibling().first_atsortingbute().as_ssortingng(); newScript->ComstackFile(luaPath.c_str()); auto callback = [&](_Physics::Trigger* sortinggger,PxTriggerPair* pairs, PxU32 count) { newScript->SelectScriptFunction("TriggerCallback"); newScript->AddParam(sortinggger->Id); auto data = (_Physics::RayCastingStats*)pairs->otherShape->userData; newScript->AddParam((PxU8)pairs->flags); newScript->AddParam(data->ID); newScript->AddParam((int)data->Type); newScript->AddParam((int)count); newScript->Go(1); return; }; ((_Physics::Trigger*)EnginePTR->iPhysics->GetPhysicObject(StartingTriggerID))->InternalCallback = callback; 

et la classe

 //class derived from LuaScript, implements a set of common use functions for AI scripts and similar. Used in the XLL parser. class ScriptedEntity : public LuaScript { protected: static const int NumberOfFunctions = 11; std::array<function,NumberOfFunctions> FunctionsArray; int m_iMethodBase; public: ScriptedEntity(LuaVirtualMachine& vm) : LuaScript (vm) { InternalEntity = new Entity; m_iMethodBase = RegisterFunction("GetEntityPos"); RegisterFunction("GetPlayerPos"); RegisterFunction("Move"); RegisterFunction("GetEntityLife"); RegisterFunction("IsPlayerVisible"); RegisterFunction("SetOrientationFromLookAt"); RegisterFunction("RotateAxisUp"); RegisterFunction("GetEntityOrientation"); RegisterFunction("Idle"); RegisterFunction("TeleportBehindPlayer"); RegisterFunction("ApplyGravity"); FunctionsArray[0] = [this](LuaVirtualMachine& vm){ return this->GetEntityPos(vm); }; FunctionsArray[1] = [this](LuaVirtualMachine& vm){ return this->GetPlayerPos(vm); }; FunctionsArray[2] = [this](LuaVirtualMachine& vm){ return this->Move(vm); }; FunctionsArray[3] = [this](LuaVirtualMachine& vm){ return this->GetEntityLife(vm); }; FunctionsArray[4] = [this](LuaVirtualMachine& vm){ return this->IsPlayerVisible(vm); }; FunctionsArray[5] = [this](LuaVirtualMachine& vm){ return this->SetOrientationFromLookAt(vm); }; FunctionsArray[6] = [this](LuaVirtualMachine& vm){ return this->RotateAxisUp(vm); }; FunctionsArray[7] = [this](LuaVirtualMachine& vm){ return this->GetEntityOrientation(vm); }; FunctionsArray[8] = [this](LuaVirtualMachine& vm){ return this->Idle(vm); }; FunctionsArray[9] = [this](LuaVirtualMachine& vm){ return this->TeleportBehindPlayer(vm); }; FunctionsArray[10] = [this](LuaVirtualMachine& vm){ return this->ApplyGravity(vm); }; ViewRayCount = 16; } virtual int ScriptCalling (LuaVirtualMachine& vm, int iFunctionNumber) { if(iFunctionNumber - m_iMethodBase > NumberOfFunctions) return 0; else return FunctionsArray[iFunctionNumber - m_iMethodBase](vm); // The user might want to add functions to the script, and that's done by overloading this function. That's why it's virtual } // Functions // Prototypes int GetEntityPos(LuaVirtualMachine& vm); int GetPlayerPos(LuaVirtualMachine& vm); int AttackPlayer(LuaVirtualMachine& vm); int Move(LuaVirtualMachine& vm); int GetEntityLife(LuaVirtualMachine& vm); int GetEntityRawDamage(LuaVirtualMachine& vm); int IsPlayerVisible(LuaVirtualMachine& vm); int SetOrientationFromLookAt(LuaVirtualMachine& vm); int RotateAxisUp(LuaVirtualMachine& vm); int GetEntityOrientation(LuaVirtualMachine& vm); int Idle(LuaVirtualMachine& vm); int TeleportBehindPlayer(LuaVirtualMachine& vm); int ApplyGravity(LuaVirtualMachine& vm); int ShootPlayer(LuaVirtualMachine& vm); // Defined bool Update(float ElapsedTime) { SelectScriptFunction("Update"); AddParam(ElapsedTime); Go(1); SelectScriptFunction("Clear"); // dummy function to clean the stack Go(); return InternalEntity->Alive; } void HandleReturns (LuaVirtualMachine& vm, const char *strFunc) { if(ssortingng(strFunc) == "Update") { // frames returns an answer of the stack lua_State *state = (lua_State *) vm; InternalEntity->Alive = lua_tonumber(state,-1) != 0; } } // Vars Entity * InternalEntity; void * EnginePTR_voidptr; int PhysicID,VisualID,PlayerID; int ViewRayCount; }; 

En outre, la mémoire se passe à l’intérieur:

  HRESULT LoadSceneSimple(ssortingng Path, int StartingModelID, int StartingInstanceID, int StartingEmmitterID, int CameraID, int StartingTriggerID, int StartingMaterialID, int StartingPhysicsID, int ShaderID, void* engPtr,function MaterialCallback, ssortingng subfolder, _Lua::ScriptedEntity * EntityBase, ssortingng LuaSubfolder); 

Vous ne faites que copier un pointeur.

Même dans ce cas, vous ne pouvez pas utiliser la memcpy la façon dont vous essayez, car vous devez connaître la taille de la mémoire associée (pointée par le pointeur), qui peut varier en fonction de la classe concrète.

Une façon de faire ce que vous souhaitez est d’append une fonction virtuelle Parent* Parent::clone() qui est ensuite remplacée par Child* Child::clone() .

Vous pouvez ensuite faire quelque chose comme Parent* new_parent = p_ptr->clone() sans avoir besoin de connaître la sous-classe.

Il est supposé que la fonction clone() se chargerait d’allouer ( new ) la mémoire de tas pour le type correct / équivalent.