C++ - 在模板方法中将 <T> 对象添加到 std::vector<abstract C> 的正确方法,无需复制 T
C++ - Proper way to add<T> obiect to std::vector<abstract C> in template method without copy T
一个程序有一个名为 Component 的接口:
class Component
{
public:
virtual void Start() = 0;
virtual void Update() = 0;
};
该接口由MeshComponent实现:
.h
#include "Component.h"
#include "Mesh.h"
class MeshComponent: public Component
{
public:
Mesh* mesh;
int a = 0; // for test
MeshComponent();
void Start();
void Update();
};
.cpp
#include "MeshComponent.h"
MeshComponent::MeshComponent(): mesh(nullptr)
{
}
void MeshComponent::Start()
{
std::cout << this << " " << a << "Start Mesh component\n";
}
void MeshComponent::Update()
{}
并在对象中使用:
#include "Mesh.h"
#include "Vector3.h"
#include "Component.h"
class Object
{
private:
void bindPosition();
void updateComponents();
std::map<std::string, std::vector<std::unique_ptr<Component>>> components;
public:
Vector3 position;
Object();
~Object();
// T:Component
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr>
void addComponent(T component) {
Component* comp = ((Component*)&component);
std::string name(typeid(T).name());
std::vector<std::unique_ptr<Component>>& arr = components[name];
arr.push_back(std::unique_ptr<Component>(comp));
T& c = (T&)*arr.back();
c.Start();
}
};
如您所见,我使用 std::map> 来包含组件。这是因为我想使用这样的东西:
parent.getComponent<Movement>(); // first one
parent.getComponents<Material>(); // array
每个组件都必须是唯一的 - 这就是它被复制的原因,我希望用户知道它被复制了。我不想复制它两次所以我想到使用 unique_ptr.
我想在删除对象时避免使用析构函数。这就是我避免使用指针的原因。
我也想避免使用移动原理图。
如果你读过这段代码,你可能会看到我的错误,即 'T component' 在超出范围时被删除(我通过写这个问题发现它。这是这个问题的主要原因)。
请教各位大神,我应该怎样做才是正确的。通过查看它,我认为我做了可以避免的不必要的转换(使用抽象 class 是地狱)或者包含组件的方式是错误的。
我指望你了。
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr>
void addComponent(T component) {
Component* comp = ((Component*)&component);
// ...
arr.push_back(std::unique_ptr<Component>(comp));
// ...
}
是的,你不能那样做。正确的方法是将其复制到一个新的唯一指针中:
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr>
void addComponent(T component) {
// ...
arr.push_back(std::make_unique<T>(comp));
// ...
}
正如你所说,虽然你不想要两个副本,所以你可以通过 const 引用来接受你的论点:
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr>
void addComponent(T const& component) {
// ...
arr.push_back(std::make_unique<T>(comp));
// ...
}
如果您发送右值,您还可以添加重载来移动对象,尽可能使其成为零副本:
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value
&& !std::is_reference<T>::value>::type* = nullptr>
void addComponent(T&& component) {
// ...
arr.push_back(std::make_unique<T>(std::move(comp)));
// ...
}
一个程序有一个名为 Component 的接口:
class Component
{
public:
virtual void Start() = 0;
virtual void Update() = 0;
};
该接口由MeshComponent实现:
.h
#include "Component.h"
#include "Mesh.h"
class MeshComponent: public Component
{
public:
Mesh* mesh;
int a = 0; // for test
MeshComponent();
void Start();
void Update();
};
.cpp
#include "MeshComponent.h"
MeshComponent::MeshComponent(): mesh(nullptr)
{
}
void MeshComponent::Start()
{
std::cout << this << " " << a << "Start Mesh component\n";
}
void MeshComponent::Update()
{}
并在对象中使用:
#include "Mesh.h"
#include "Vector3.h"
#include "Component.h"
class Object
{
private:
void bindPosition();
void updateComponents();
std::map<std::string, std::vector<std::unique_ptr<Component>>> components;
public:
Vector3 position;
Object();
~Object();
// T:Component
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr>
void addComponent(T component) {
Component* comp = ((Component*)&component);
std::string name(typeid(T).name());
std::vector<std::unique_ptr<Component>>& arr = components[name];
arr.push_back(std::unique_ptr<Component>(comp));
T& c = (T&)*arr.back();
c.Start();
}
};
如您所见,我使用 std::map
parent.getComponent<Movement>(); // first one
parent.getComponents<Material>(); // array
每个组件都必须是唯一的 - 这就是它被复制的原因,我希望用户知道它被复制了。我不想复制它两次所以我想到使用 unique_ptr.
我想在删除对象时避免使用析构函数。这就是我避免使用指针的原因。 我也想避免使用移动原理图。
如果你读过这段代码,你可能会看到我的错误,即 'T component' 在超出范围时被删除(我通过写这个问题发现它。这是这个问题的主要原因)。
请教各位大神,我应该怎样做才是正确的。通过查看它,我认为我做了可以避免的不必要的转换(使用抽象 class 是地狱)或者包含组件的方式是错误的。
我指望你了。
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr>
void addComponent(T component) {
Component* comp = ((Component*)&component);
// ...
arr.push_back(std::unique_ptr<Component>(comp));
// ...
}
是的,你不能那样做。正确的方法是将其复制到一个新的唯一指针中:
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr>
void addComponent(T component) {
// ...
arr.push_back(std::make_unique<T>(comp));
// ...
}
正如你所说,虽然你不想要两个副本,所以你可以通过 const 引用来接受你的论点:
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr>
void addComponent(T const& component) {
// ...
arr.push_back(std::make_unique<T>(comp));
// ...
}
如果您发送右值,您还可以添加重载来移动对象,尽可能使其成为零副本:
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value
&& !std::is_reference<T>::value>::type* = nullptr>
void addComponent(T&& component) {
// ...
arr.push_back(std::make_unique<T>(std::move(comp)));
// ...
}