通常的模式是通过你的层次结构的虚拟克隆方法。
如果这是不可能的,是否有任何人都知道的解决这个问题的非丑陋解决方案?
您还可以使用基于复制构造函数的克隆函数的模板实例化。这是我在正在编写的 Web 服务器中使用的解决方案(宠物项目):
#pragma once
#include <memory>
#include <cassert>
#include <functional>
#include <stdexcept>
#include <vector>
namespace stdex {
inline namespace details {
/// @brief Deep copy construct from (Specialized&)*src
///
/// @retval nullptr if src is nullptr
/// @retval Specialized clone of *src
///
/// @note Undefined behavior src does not point to a Specialized*
template<typename Base, typename Specialized>
Base* polymorphic_clone (const Base* src) {
static_assert(std::is_base_of<Base, Specialized>::value,
"Specialized is not a specialization of Base");
if (src == nullptr)
return nullptr;
return new Specialized{ static_cast<const Specialized&>(*src) };
}
}
/// @brief polymorphic reference interface over a base class
///
/// Respects polymorphic behavior of class ref.
/// Instances have deep copy semantics (clone) and
/// "[const] Base&" interface
///
/// @note Not regular: no trivial way to implement non-intrusive equality
///
/// @note safe to use with standard containers
template<typename Base>
class polymorphic final
{
public:
/// Functor capable to convert a Base* to it's specialized type
/// and clone it (intrusive implementation can be used)
typedef std::function<Base* (const Base*)> clone_functor;
/// @brief construct (takes ownership of ptr)
template<typename Specialized, typename CloneSpecialized>
polymorphic(Specialized* ptr, CloneSpecialized functor) noexcept
: instance_{ptr}, clone_{std::move(functor)}
{
static_assert(std::is_base_of<Base, Specialized>::value,
"Specialized is not a specialization of Base");
static_assert(
std::is_constructible<clone_functor, CloneSpecialized>::value,
"CloneSpecialized is not valid for a clone functor");
}
// not implemented: UB cloning in case client provides specialized ptr
// polymorphic(Base* ptr);
polymorphic()
: polymorphic{ nullptr, clone_functor{} }
{
}
polymorphic(polymorphic&&) = default;
polymorphic(const polymorphic& other)
: polymorphic{std::move(other.clone())}
{
}
polymorphic& operator=(polymorphic other)
{
std::swap(instance_, other.instance_);
std::swap(clone_, other.clone_);
return *this;
}
~polymorphic() = default;
/// @brief Cast to contained type
/// @pre instance not moved
/// @pre *this initialized with valid instance
operator Base&() const
{
assert(instance_.get());
return *instance_.get();
}
/// @brief Cast to contained type
/// @pre instance not moved
/// @pre *this initialized with valid instance
operator const Base&() const
{
assert(instance_.get());
return *instance_.get();
}
private:
polymorphic clone() const
{
return polymorphic{
clone_(instance_.get()), clone_functor{clone_}
};
}
std::unique_ptr<Base> instance_;
clone_functor clone_;
};
template<typename Base, typename Specialized, typename CF>
polymorphic<Base> to_polymorphic(Specialized&& temp, CF functor)
{
static_assert(std::is_base_of<Base, Specialized>::value,
"Specialized is not a specialization of Base");
typedef typename polymorphic<Base>::clone_functor clone_functor;
auto ptr_instance = std::unique_ptr<Base>{
new Specialized{std::move(temp)}
};
auto clone_instance = clone_functor{std::move(functor)};
return polymorphic<Base>{ptr_instance.release(), clone_instance};
}
template<typename Base, typename Specialized>
polymorphic<Base> to_polymorphic(Specialized&& temp)
{
static_assert(std::is_base_of<Base, Specialized>::value,
"Specialized is not a specialization of Base");
return to_polymorphic<Base,Specialized>(
std::move(temp), details::polymorphic_clone<Base,Specialized>
);
}
template<typename Base, typename Specialized, typename ...Args>
polymorphic<Base> to_polymorphic(Args ...args)
{
static_assert(std::is_constructible<Specialized, Args...>::value,
"Cannot instantiate Specialized from arguments");
return to_polymorphic<Base,Specialized>(
std::move(Specialized{std::forward<Args...>(args...)}));
}
template<typename Base> using polymorphic_vector =
std::vector<polymorphic<Base>>;
template<typename Base, typename ...Args>
polymorphic_vector<Base> to_polymorphic_vector(Args&& ...args)
{
return polymorphic_vector<Base>{to_polymorphic<Base>(args)...};
}
} // stdex
使用示例:
stdex::polymorphic_vector<view> views = // explicit type for clarity
stdex::to_polymorphic_vector(
echo_view{"/echo"}, // class echo_view : public view
directory_view{"/static_files"} // class directory_view : public view
);
for(auto& v: views)
if(v.matches(reuqest.url())) // bool view::matches(...);
auto response = view.handle(request); // virtual view::handle(...) = 0;
这个限制:
如果您使用多重继承,请勿使用 stdex::details::polymorphic_clone。改为基于 dynamic_cast 编写实现,并使用to_polymorphic(Specialized&& temp, CF functor)。