派生类型的自动静态调用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了派生类型的自动静态调用相关的知识,希望对你有一定的参考价值。

有没有人知道一种方法,使派生类自动实例化一个模板类型的静态变量(这要么不需要派生类的编写器,或强迫他调用这个静态方法,以使派生类定义有效)。

这可能是不可能理解的,我会尝试更好地定义它。

基本上我有一个全局工厂类,带有一个名为registerType的模板化函数。对于从Entity派生的每个类,我需要使用派生类型的模板参数调用此函数。目前,我必须在某个init函数中手动执行此操作,这会导致对此函数的大量调用,这违反了我的模板原则。

所以我有这个:

class Factory
{
  template <typename EntityType>
  registerEntityType();
};

void someInitFunction()
{
   /// All of these are derived from Entity
  gFactory.registerEntityType<EntityType1>();
  gFactory.registerEntityType<EntityType2>();
  gFactory.registerEntityType<EntityType3>();
  /// and so on
}

而我宁愿这样:

class Factory
{
  template <typename EntityType>
  registerEntityType();
};

class Entity // Abstract
{
    /// This function should be called automatically with the derived 
    /// type as a parameter
    SomeStaticConstructor<MDerivedType>() 
    {
      gFactory.registerEntityType<MDerivedType>();
    }
};

编辑:这是不起作用的静态重复模板代码:

这是我的基类,以及用于自动注册东西的类

template <typename DerivedType>
class Registrar
{
    public:
        Registrar();
        void check();
};
template <typename Product, typename DerivedType>
class AbstractFactory: public AbstractFactoryBase<Product>
{
    public:
        AbstractFactory();
        ~AbstractFactory();
    private:
        static Registrar<DerivedType> registrar;
};

注册商的构造函数

template <typename DerivedType>
Registrar<DerivedType>::Registrar()
{
    std::cout << DerivedType::name() << " initialisation" << std::endl;
    g_AbstractFactories.registerFactoryType<DerivedType>(DerivedType::name());
}

和派生类型

class CrateFactory : public AbstractFactory<Entity, CrateFactory>
{
    public:
        CrateFactory(FactoryLoader* loader);
        virtual ~CrateFactory();
        Entity* useFactory(FactoryParameters* parameters);
        static std::string name()
        {
            return "CrateFactory";
        }
答案

我推荐一种CTRP支持的方法:

// Entity.h
class EntityBase
{ // abstract
};

template<class Derived>
class Entity
  : public EntityBase
{ // also abstract thanks to the base
  static char _enforce_registration; // will be instantiated upon program start
};

// your actual types in other headers
class EntityType1
  : public Entity<EntityType1>
{ // automatic registration thanks to the _enforce_registration of the base
  // ...
};

// Entity.cpp
#include "Entity.h"

template<class T>
char RegisterType(){
  GetGlobalFactory().registerEntityType<T>();
  return 0; // doesn't matter, never used.
}

template<class Derived>
char Entity<Derived>::_enforce_registration = RegisterType<Derived>();

但是,如您所见,您现在需要让您的工厂通过GetGlobalFactory函数,该函数延迟初始化工厂以确保在强制注册发生之前已初始化:

Factory& GetGlobalFactory(){
  static Factory _factory;
  return _factory;
}
另一答案

您可以使用混合和CRTP获得所需的内容。

但首先,您需要处理“初始化顺序”问题。为了确保在尝试使用它之前存在gFactory,你真的需要使它成为一个合适的“单例”类,如下所示:

class Factory {
public:
    static Factory &getFactory() { static Factory f; return f; }
    template <typename EntityType>
    void registerEntityType() { ... }
};

然后“混合”看起来像这样:

template <typename T>
class EntityMixin {
private:
    struct RegisterMe {
        RegisterMe() { Factory::getFactory().registerEntityType<T>(); }
    };
    EntityMixin() {
        static RegisterMe r;
    }
};

你会像这样使用它:

class EntityType1 : public Entity, EntityMixin<EntityType1> { ... };
class EntityType2 : public Entity, EntityMixin<EntityType2> { ... };
class EntityType3 : public Entity, EntityMixin<EntityType3> { ... };

[更新]

您还可以采用Xeo / Merlyn创建qa​​zxswpoi的想法,将EntityBase重命名为EntityMixin,并避免从两个地方继承。我实际上认为我的原始提案更清楚;你甚至可以调用mixin Entity并将其粘贴到你要注册的任何课程上。

但Xeo / Merlyn版本看起来像这样:

FactoryMixin

任何解决方案的关键是CRTP并谨慎使用静态局部变量以避免初始化顺序问题。

另一答案

如果有人仍然感兴趣,我想出来了。除非使用静态模板成员变量,否则不会自动实例化它们。我需要在调用构造函数之前对其进行实例化,因此我无法将其设置为静态本地。解决方案是使它成为一个静态模板成员变量,然后在成员函数中使用它(如果需要,只需调用一个空函数)(我使用构造函数)。这会强制编译器为所声明的每个模板参数实例化静态,因为实例化的构造函数代码使用它,例如:

我的注册表类,其空白函数用于调用

class Factory {
    public:
    static Factory &getFactory() { static Factory f; return f; }
    template <typename EntityType>
    void registerEntityType() { ... }
};

class EntityBase { ... } ;

template <typename T>
class Entity : public EntityBase {
private:
    struct RegisterMe {
        RegisterMe() { Factory::getFactory().registerEntityType<T>(); }
    };
    Entity() {
        static RegisterMe r;
    }
};

class EntityType1 : public Entity<EntityType1> { ... };
class EntityType2 : public Entity<EntityType2> { ... };
class EntityType3 : public Entity<EntityType3> { ... };

我的班级我想要注册。

template <typename DerivedType>
class Registrar
{
    public:
        Registrar();
        void check(){}
};

注册商的构造函数

template <typename Product, typename DerivedType>
class AbstractFactory: public AbstractFactoryBase<Product>
{
    public:
        AbstractFactory();
        ~AbstractFactory();
    private:
        static Registrar<DerivedType> registrar;
};

和我的类构造函数

template <typename DerivedType>
Registrar<DerivedType>::Registrar()
{
    std::cout << DerivedType::name() << " initialisation" << std::endl;
    g_AbstractFactories.registerFactoryType<DerivedType>(DerivedType::name());
}

以上是关于派生类型的自动静态调用的主要内容,如果未能解决你的问题,请参考以下文章

为啥可以从指向实例化基类对象的强制转换指针调用非静态派生类方法?

派生类中的静态方法可以在 C++ 中调用受保护的构造函数吗?

利用虚函数实现多态的方式:动态绑定

ABPExtensions后缀扩展方法

如何初始化派生类中的静态成员?

如何在调用基类的静态函数之前设置派生静态成员