The idea is to provide a type that can only be instantiated by the factory and to expect this type as an argument in every constructor of the base class.
This way, the constructors of the derived classes have to pass this argument to the constructor of the base class.
Since they cannot instantiate this argument by themselves, the only way is to expect this argument too, thus these constructors can only be called from the factory.
Note that, in this example, I suppose that you use a hierarchy of types in order to achieve dynamic polymorphism; this is absolutely not mandatory.
If you are not interested in dynamic polymorphism, the factory function should have a result with type std::unique_ptr<ChildType>
.
/**
g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
-pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <memory> // std::unique_ptr
// #include <type_traits> // std::is_base_of_v
#include <iostream>
#include <string>
#include <vector>
class Parent
{
public:
// ensure correct destruction of derived instances
virtual ~Parent() =default;
// forbid copy/move in order to prevent from slicing
Parent & operator=(const Parent &) =delete;
Parent(const Parent &) =delete;
Parent & operator=(Parent &&) =delete;
Parent(Parent &&) =delete;
template<typename ChildType>
static
std::unique_ptr<Parent> // the actual type can be Parent or a derived type
create_instance()
{
// this check is redundant because FactoryTag in only
// accessible to types derived from Parent
// static_assert(std::is_base_of_v<Parent, ChildType>);
#if 1
return std::unique_ptr<Parent>{new ChildType{FactoryTag{}}};
#else
// contructor is inaccessible to std::make_unique()
return std::make_unique<ChildType>(FactoryTag{});
#endif
}
virtual
std::string
show() const
{
return std::to_string(i_);
}
protected:
class FactoryTag
{
friend class Parent; // only this class can instantiate this tag
FactoryTag() {};
};
Parent(FactoryTag) // a tag is mandatory for instantiation
: i_{1}
{
// nothing more to be done
}
private:
int i_;
};
class Child: public Parent
{
public:
Child(FactoryTag tag)
: Parent{tag}
, j_{2.3}
{
// nothing more to be done
}
/*
Child()
: Parent{} // FactoryTag is expected
, j_{4.5}
{
// nothing more to be done
}
Child()
: Parent{FactoryTag{}} // constructor of FactoryTag is private
, j_{6.7}
{
// nothing more to be done
}
*/
std::string
show() const override
{
return Parent::show()+' '+std::to_string(j_);
}
private:
double j_;
};
int
main()
{
const auto p=Parent::create_instance<Parent>();
const auto c=Parent::create_instance<Child>();
std::cout << p->show() << '\n'; // displays 1
std::cout << c->show() << '\n'; // displays 1 2.300000
auto v=std::vector<std::unique_ptr<Parent>>{};
v.emplace_back(Parent::create_instance<Parent>());
v.emplace_back(Parent::create_instance<Child>());
for(const auto &e: v)
{
std::cout << e->show() << '\n'; // displays 1
} // then 1 2.300000
return 0;
}
And, if the Factory
needs to be a complex object separated from Parent
(not just a simple static function), you can just state friend class Factory;
in Parent
and in FactoryTag
.
Then you can remove create_instance()
from Parent
and provide something like this:
class Factory
{
public:
template<typename ChildType>
std::unique_ptr<Parent> // the actual type can be Parent or a derived type
create_instance()
{
// this check is redundant because FactoryTag in only
// accessible to types derived from Parent
// static_assert(std::is_base_of_v<Parent, ChildType>);
#if 1
return std::unique_ptr<Parent>{new ChildType{Parent::FactoryTag{}}};
#else
// contructor is inaccessible to std::make_unique()
return std::make_unique<ChildType>(Parent::FactoryTag{});
#endif
}
};