C++ 所有派生类的显式实例化
我有一个C++ 所有派生类的显式实例化,c++,templates,instantiation,C++,Templates,Instantiation,我有一个组件类: class Component { } 然后是继承自碰撞器的碰撞器类: class Collider :public Component { } 以及从碰撞器继承的球体碰撞器: class SphereCollider :public Collider { } 最后是一个GameObject类,您可以使用它添加或删除组件 GameObject.h标题: 除非我还添加以下内容,否则不会编译: template Collider &GameObject::Ge
组件
类:
class Component
{
}
然后是继承自碰撞器的碰撞器
类:
class Collider :public Component
{
}
以及从碰撞器继承的球体碰撞器
:
class SphereCollider :public Collider
{
}
最后是一个GameObject
类,您可以使用它添加或删除组件
GameObject.h标题:
除非我还添加以下内容,否则不会编译:
template Collider &GameObject::GetComponent<Collider>();
template Collider &GameObject::AddComponent<Collider>();
模板碰撞器&GameObject::GetComponent();
模板碰撞器&GameObject::AddComponent();
在GameObject.cpp源文件中
由于使用GetComponent
和AddComponent
函数的所有内容都继承自Component
类,因此是否有方法自动为继承自Component
类的每个类进行显式实例化
我尝试了模板组件&GameObject::GetComponent()代码>
和模板组件&GameObject::AddComponent()代码>但这不起作用,只给了我“未解析的外部符号”错误
目前我唯一的选择是将所有模板函数放在头文件中,但这将为GetComponent
和AddComponent
模板函数公开一个重要的代码 不,不可能
1) template Component&GameObject::GetComponent()
仅是具体的组件
类的显式实例化。编译器找不到纯虚拟方法的定义,所以会出现链接器错误
2) 如果不添加相应的include,则从组件派生的某些类在GameObject.cpp中可能无法访问。因此,在一般情况下,编译器甚至理论上也无法获得所有继承者的列表,因为这些信息仅在链接时可用
由于使用GetComponent
和AddComponent
函数的所有内容都继承自Component
类,因此是否有方法自动为继承自Component
类的每个类进行显式实例化
简单的回答是“不”
从组件
派生类正好实现了这一点。您得到的是一个派生类——除此之外什么都没有。如果基类具有在派生类中重写的virtual
成员函数,则可以在派生类中实现该行为
任何额外的东西都必须编码。需要编写的额外代码的数量取决于额外的功能和您提供的框架
这里有一个可能的方法来实现你的目标。请注意,这使用了动态\u cast
,如果不小心,可能会失败
class Component
{
public:
virtual ~Component() {}
};
#include <map>
// Implement GameObject with no knowledge of any of the classes derived
// from Component. That will be one sure fire way of making sure that it can
// be used for any class derived from Component.
class GameObject
{
public:
//Add functionality
template <class T>
T& AddComponent()
{
T* obj = new T{};
AddComponent(getTypeID<T>(), obj);
return *obj;
}
//Get functionality
template <typename T>
T& GetComponent()
{
T* obj = dynamic_cast<T*>(GetComponent(getTypeID<T>()));
return *obj;
}
private:
// If necessary, the implementation can be moved to a .cpp file.
void AddComponent(int typeID, Component* obj)
{
components[typeID] = obj;
}
// If necessary, the implementation can be moved to a .cpp file.
Component* GetComponent(int typeID)
{
return components[typeID];
}
// Key function.
// It gets a unique integer for every type.
template <class T>
static int getTypeID()
{
static int typeID = getNextID();
return typeID;
}
// If necessary, the implementation can be moved to a .cpp file.
static int getNextID()
{
static int nextID = 0;
return ++nextID;
}
std::map<int, Component*> components;
};
class Collider : public Component
{
};
class SphereCollider :public Collider
{
};
int main()
{
GameObject go;
go.AddComponent<Collider>();
go.AddComponent<SphereCollider>();
Collider c = go.GetComponent<Collider>();
SphereCollider sc = go.GetComponent<SphereCollider>();
}
类组件
{
公众:
虚拟~Component(){}
};
#包括
//在不了解任何派生类的情况下实现GameObject
//来自组件。这将是确保它能够
//可用于从组件派生的任何类。
类游戏对象
{
公众:
//添加功能
样板
T&AddComponent()
{
T*obj=新的T{};
AddComponent(getTypeID(),obj);
返回*obj;
}
//获取功能
样板
T&GetComponent()
{
T*obj=dynamic_cast(GetComponent(getTypeID());
返回*obj;
}
私人:
//如有必要,可以将实现移动到.cpp文件中。
void AddComponent(int-typeID,Component*obj)
{
组件[typeID]=obj;
}
//如有必要,可以将实现移动到.cpp文件中。
组件*GetComponent(int类型ID)
{
返回组件[typeID];
}
//关键功能。
//它为每种类型获取一个唯一的整数。
样板
静态int getTypeID()
{
静态int-typeID=getNextID();
返回typeID;
}
//如有必要,可以将实现移动到.cpp文件中。
静态int getNextID()
{
静态int nextID=0;
return++nextID;
}
地图组件;
};
类碰撞器:公共组件
{
};
类球对撞机:公共对撞机
{
};
int main()
{
游戏对象围棋;
go.AddComponent();
go.AddComponent();
碰撞器c=go.GetComponent();
SphereCollider sc=go.GetComponent();
}
get
@NeilButterworth我之所以需要使用模板,是因为我需要使用模板,因为我正在寻找一种特殊的语法,比如gameObject.AddComponent()<代码>就像C++,但是C++。我认为没有其他方法可以在没有模板的情况下获得语法。@StoryTeller说得对。我只希望那些使用统一但程序C++的人能够使用它或者将他们的代码移植到C++中。@程序员然后No。你基本上想生成一个没有源代码的函数模板的新实例。您要么需要提供用户将需要的模板的任何实例,要么需要为他们的编译器提供源代码以完成缺少的实例。我已经有了T&AddComponent()
和T&GetComponent()
函数通过dynamic_cast
和一种机制实现,该机制确保两个函数都不能返回null
,因为这两个函数都返回引用。我只是在寻找一种方法来隐藏其中的长代码。我讨厌不接受和接受另一个答案,但你的答案是我要找的。它有一个变通方法,我可以使用AddComponent(int-typeID,Component*obj)
隐藏长代码。Thanks@Programmer,很高兴听到我能帮忙。
GameObject gameObject;
SphereCollider sCollider1 = gameObject.AddComponent<SphereCollider>();
SphereCollider sCollider2 = gameObject.GetComponent<SphereCollider>();
Component sCollider3 = gameObject.GetComponent<Component>();
Collider sCollider = gameObject.GetComponent<InnoEngine::Collider>();
template Collider &GameObject::GetComponent<Collider>();
template Collider &GameObject::AddComponent<Collider>();
class Component
{
public:
virtual ~Component() {}
};
#include <map>
// Implement GameObject with no knowledge of any of the classes derived
// from Component. That will be one sure fire way of making sure that it can
// be used for any class derived from Component.
class GameObject
{
public:
//Add functionality
template <class T>
T& AddComponent()
{
T* obj = new T{};
AddComponent(getTypeID<T>(), obj);
return *obj;
}
//Get functionality
template <typename T>
T& GetComponent()
{
T* obj = dynamic_cast<T*>(GetComponent(getTypeID<T>()));
return *obj;
}
private:
// If necessary, the implementation can be moved to a .cpp file.
void AddComponent(int typeID, Component* obj)
{
components[typeID] = obj;
}
// If necessary, the implementation can be moved to a .cpp file.
Component* GetComponent(int typeID)
{
return components[typeID];
}
// Key function.
// It gets a unique integer for every type.
template <class T>
static int getTypeID()
{
static int typeID = getNextID();
return typeID;
}
// If necessary, the implementation can be moved to a .cpp file.
static int getNextID()
{
static int nextID = 0;
return ++nextID;
}
std::map<int, Component*> components;
};
class Collider : public Component
{
};
class SphereCollider :public Collider
{
};
int main()
{
GameObject go;
go.AddComponent<Collider>();
go.AddComponent<SphereCollider>();
Collider c = go.GetComponent<Collider>();
SphereCollider sc = go.GetComponent<SphereCollider>();
}