好吧,这是我提出的一些黑客攻击,但我在现实代码中使用它时遇到了一些问题.这是我想要做的一个有效例子
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 << "From child, Val is: ";
val->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 < 100;n++)
{
Parent * new_ptr = nullptr;
//memcpy ( &new_ptr, &p_ptr, sizeof(Parent) );
memcpy_s( &new_ptr, sizeof(p_ptr),&p_ptr, sizeof(p_ptr) );
new_ptr->printVal();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我使用memcpy或memcpy_s,此示例有效.我的想法是将一个用户派生类传递给一个函数,然后创建几个副本,但由于我不知道在编译时派生类类型,我想到了这一点.正如我所说,这完全有效,我把它复制到我的引擎,在那里我想使用它,而且我有一些记忆问题从无处出现,它们似乎与那个黑客有关.使用memcpy_s解决了其中一些问题.这是"好"的事情,还是有更好的方法?
这是"真实世界"代码
_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));
string luaPath = transforms.next_sibling().next_sibling().first_attribute().as_string();
newScript->CompileFile(luaPath.c_str());
auto callback = [&](_Physics::Trigger* trigger,PxTriggerPair* pairs, PxU32 count)
{
newScript->SelectScriptFunction("TriggerCallback");
newScript->AddParam(trigger->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;
Run Code Online (Sandbox Code Playgroud)
和班级
//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<int(LuaVirtualMachine& vm)>,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(string(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;
};
Run Code Online (Sandbox Code Playgroud)
另外,memcpy发生在里面:
HRESULT LoadSceneSimple(string Path,
int StartingModelID,
int StartingInstanceID,
int StartingEmmitterID,
int CameraID,
int StartingTriggerID,
int StartingMaterialID,
int StartingPhysicsID,
int ShaderID,
void* engPtr,function<void(_X3D::BaseEffect* effect, _X3D::MaterialValues* matt,int ObjectID,int ShaderID)> MaterialCallback,
string subfolder,
_Lua::ScriptedEntity * EntityBase, string LuaSubfolder);
Run Code Online (Sandbox Code Playgroud)
你只是在复制一个指针.
即便如此,你也无法使用memcpy你想要的方式,因为你需要知道相关内存的大小(指针指向的内存),这可能因具体类而异.
做你想要的一种方法是添加一个虚拟Parent* Parent::clone()函数然后被覆盖Child* Child::clone().
然后你可以做一些事情,Parent* new_parent = p_ptr->clone()而不需要知道子类.
假设该clone()函数将负责new为正确/等效类型分配堆内存.