我们需要一个C ++解决方案,该解决方案必须能够执行以下操作:
给定一个特殊类型的字符串,假设为“ A”,我们想找到所有从“ A”派生的类型。
从“ A”派生的类型之外实例化新对象。
例如。可以说我们有一个类VehicleEntity。 VehicleEntity具有子类,PassangerCarEntity,TruckEntity,TrainEntity,BoatEntity。
我们无法确定可能存在哪些车辆实体,因为可以添加一个包含更多VehicleEntities的库。例如。部署后,可以添加从VehicleEntity派生的AirplaneEntity。
在应用程序中,当用户想要选择VehicleEntity时,用户应该能够选择从VehicleEntity派生的任何实体。这包括PassangerCarEntity,TruckEntity,TrainEntity,BoatEntity和AirplaneEntity。
用户选择一个实体,比方说AirplaneEntity,必须实例化一个AirplaneEntity类型的新对象。
下面是C#中我们要在C ++中实现的概念示例。
在C#中,可以按以下方式检索下拉列表的项目:
Type vehicleEntityType = typeof(VehicleEntity);
List<Type> types = new List<Type>();
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
types.AddRange(assembly.GetTypes().Where(x => vehicleEntityType.IsAssignableFrom(x) && !x.IsGenericType && !x.IsAbstract));
dropDownBox.ItemList = types;
//To instantiate the object:
List<VehicleEntity> vehicleList = new List<VehicleEntity>();
Type newVehicleType = (Type)dropDownBox.SelectedItem;
object newVehicle = Activator.CreateInstance(newVehicleType ); // default constructor used, parameterless constructors for vehicles.
vehicleList.Add(newVehicle);
标准C ++似乎无法执行此操作,因为它没有在其对象上存储任何元数据。有外部库可以反映C ++。 RTTI和boost.Mirror似乎无法做到这一点。
我敢肯定,我们不是唯一出现此问题并且存在解决方案的人。有哪些解决方案可以解决我们的问题?外部库或其他方式。
最佳答案
对我来说,使用反射来完成这项任务似乎有点过度设计。从另一个角度看问题:您想知道什么时候有人从您的班级派生的。这可以通过以下方式(但不限于)来实现:
创建静态VehicleRepository
类。
准备以下功能:
static VehicleContext * VehicleRepository::Register(string newName, std::function<Vehicle * (void)> vehicleCtor)
该方法的任务是注册可用的新车辆类型。
在VehicleBase的基类中要求VehicleContext:
VehicleBase::VehicleBase(VehicleContext * newContext)
为派生类创建静态ctor,以获取上下文:
static VehicleContext * context;
static NewVehicle()
{
context = VehicleBase::Register("NewVehicle", []() { return new NewVehicle(); });
}
C ++没有静态构造函数,但是您可以通过以下方式仿真它们:Static constructor in c++。同样,此代码可以放在应用程序或库的某些初始化部分中。
在实例化新的派生类时使用上下文:
NewVehicle::NewVehicle()
: base(NewVehicle::context)
{
}
这是确保每辆车都能在VehicleRepository中正确注册的简单方法。您还将拥有所有已注册车辆的集中存储库,以及用于创建它们的适当构造函数。
通常,您必须创建一个遵循以下规则的架构:
如果实例化之前没有在某个全局存储库中注册该类,则实例化派生类应该是不可能的。
上面介绍的另一种方法:
BaseVehicle::BaseVehicle(Token token)
{
// token is passed from the derived class
if (!GlobalRepository.IsRegistered(token))
throw new std::exception("Vehicles should be registered prior to instantiating!");
}
令牌可以是类名称,与该类关联的GUID或其他名称。值得深思的:)
关于c++ - 反射(reflect)C++中基类的子类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20210777/