Jump to content
  • Advertisement
Sign in to follow this  
Alundra

Factory pattern without virtual

This topic is 2071 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all,

Factory pattern is a common way to have flexible system.

Factory pattern is three functions : GetTypeID,GetTypeName,Clone.

GetTypeID and GetTypeName can be not virtual if set in the base constructor.

class IBase
{
public:

  IBase(const uint32 TypeID, const string TypeName) :
  m_TypeID(TypeID),
  m_TypeName(TypeName)
  {
  }

  uint32 GetTypeID() const
  {
    return m_TypeID;
  }
  
  string GetTypeName() const
  {
    return m_TypeName;
  }

private:

  uint32 m_TypeID;
  string m_TypeName;
};

About the Clone function, it's defined like that :

virtual IBase* Clone() const = 0;

Is it possible to have the clone function without virtual ? Maybe a template way ?

Thanks

Edited by Alundra

Share this post


Link to post
Share on other sites
Advertisement

Hi all,

Factory pattern is a common way to have flexible system.

Factory pattern is three functions : GetTypeID,GetTypeName,Clone.

GetTypeID and GetTypeName can be not virtual if set in the base constructor.

class IBase
{
public:

  IBase(const uint32 TypeID, const string TypeName) :
  m_TypeID(TypeID),
  m_TypeName(TypeName)
  {
  }

  uint32 GetTypeID() const
  {
    return m_TypeID;
  }
  
  string GetTypeName() const
  {
    return m_TypeName;
  }

private:

  uint32 m_TypeID;
  string m_TypeName;
};

About the Clone function, it's defined like that :

virtual IBase* Clone() const = 0;

Is it possible to have the clone function without virtual ? Maybe a template way ?

Thanks

 

Depends. If you want the type to be resolved at runtime, you need some kind of mechanism to select the correct cloning method and you'd be unlikely to be able to implement something better than the built-in virtual methods.

 

If you are looking to resolve this at compile time, why do you need to use an abstract interface anwyay? Just use concrete factories.

Share this post


Link to post
Share on other sites
You're not going to get away from virtual if you need a true run-time factory. At best could replace the virtual function with a function pointer or std::function, but that's unlikely to be much of an improvement.

You could use a template to simplify writing of the factories. Something like the following untested brain dump:
 
class IFactoryBase {
  virtual void* DoCreate() const = 0;

public:
  template <typename T>
  std::unique_ptr<T> CreateTyped() const {
    // add check that T is same or base of this factory's object type

    std::unique_ptr<T>(static_cast<T*>(DoCreate()));
  }
};

template <typename T>
class ConcreteFactory : public IFactoryBase
{
  virtual void* DoCreate() const {
    return new T();
  }

public:
  std::unique_ptr<T> Create() const {
    return std::unique_ptr<T>(DoCreate());
  }
};

int main() {
  // you can directly use the factory
  ConcreteFactory<Foo> fooFactory;
  std::unique_ptr<Foo> f = fooFactory.Create();

  // or use the base interface and a type adaptor function
  std::unique_ptr<BaseOfFoo> b = generic.CreateTyped<BaseOfFoo>();
For static factories (compile-time factories), you can use policy classes instead. These are just structs that implement their Create() method as a static function, or a factory that is indended to be instantiated. Something like:
 
template <typename T, typename U = std::unique_ptr<T>>
struct StaticFactory {
  using object_type = T;
  using pointer_type = U;

  static pointer_type Create() const { return pointer_type(new T); }
};

template <typename Factory>
void some_generic_code() {
  auto ptr = Factory::Create();
  // do stuff with ptr
}
Much more simply in most cases needing this kind of stuff in real games would just be to have a single global function that #ifdefs its implementation, e.g.
 
// graphicsdevice.h
void InitGraphics();

// graphicsdeviced3d11.cpp
#if PLATFORM_WINDOWS && !FORCE_OPENGL
#include <d3d11.h>
void InitGraphics() {
  CreateDeviceAndSwapChain(...)
}
#endif

// graphicsdevicexenon.cpp
#if PLATFORM_XBOX360
#include "xenonstuff.h"
void InitGraphics() {
  ...
}
#endif

// graphicsdevicegl.cpp
#if PLATFORM_LINUX || PLATFORM_IOS || FORCE_OPENGL
#include "glew.h"
void InitGraphics() {
  CreateContext(...);
}
#endif
In such a setup InitGraphics can be thought of as a factory even though it doesn't follow the textbook pattern.

Share this post


Link to post
Share on other sites

If the whole idea behind the factory is that it returns polymorphic objects that are derived from IBase, then it will have to have some virtual members.

BTW, IBase should most likely have a virtual destructor!

 

What's your reason for using this kind of factory? What does your overall design look like?

There are other kinds of factories, like Sean has mentioned, where there is no run-time polymorphism involved at all.

Share this post


Link to post
Share on other sites

I use this kind of factory to save/load and have the editor flexible.

The create menu of the editor is just a list from Factory<IActor>.

In the LoadFromFile of Scene, it's used too to load based on Type.

IParticleAffector is in factory too and IActorComponent too.

Each class has : GetTypeID,GetTypeName,Clone,ReadData,WriteData.

Actually Clone is the only virtual, since I use a PropertySystem, each property has Read/Write virtual.

Other class only store an array of property so no need of virtual here, all is auto.

Edited by Alundra

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!