C++;避免调用抽象基类';s构造函数 目前,我正在用C++(C++ 11标准)来构建一个库,我一直在努力弄清楚如何使我的设计更实用。我有以下抽象类E template<typename K> class E { public: virtual ~E() {}; virtual void init() = 0; virtual void insert(const K& k) = 0; virtual size_t count() const = 0; virtual void copy(const E<Key>& x) = 0; };
和C++;避免调用抽象基类';s构造函数 目前,我正在用C++(C++ 11标准)来构建一个库,我一直在努力弄清楚如何使我的设计更实用。我有以下抽象类E template<typename K> class E { public: virtual ~E() {}; virtual void init() = 0; virtual void insert(const K& k) = 0; virtual size_t count() const = 0; virtual void copy(const E<Key>& x) = 0; };,c++,c++11,C++,C++11,和ETwo:public E,它类似于EOne。另外,还有一个不同的类J,它有一个成员std::vector,需要在构造过程中实例化: template<typename K> class J { public: J(size_t n, const E<K>& e) : v(n, e) {} private: std::vector<E<K>> v; } 但是,上面的代码没有编译,编译器抱怨我无法实例化抽
ETwo:public E
,它类似于EOne
。另外,还有一个不同的类J
,它有一个成员std::vector
,需要在构造过程中实例化:
template<typename K>
class J
{
public:
J(size_t n, const E<K>& e) : v(n, e)
{}
private:
std::vector<E<K>> v;
}
但是,上面的代码没有编译,编译器抱怨我无法实例化抽象类(我使用的是vc++但我相信在其他编译器上也会遇到同样的错误)。因此,我的问题是如何克服这个问题?你对我如何使我的设计更实用有什么建议吗
谢谢因为std::vector v
需要类E的静态实例化,它永远不会编译(正如您已经正确注意到的)。要使它发挥作用,应该使用
std::vector v代码>
相反。它可以动态存储对象EOne
和ETwo
,同时可以使用类型为E
的指针来引用它们。要向向量添加新对象,可以使用push_back:
v.push_back(std::make_shared<EOne<K>>{});
v.push_back(std::make_shared{});
要在类型之间转换,可以对智能指针使用动态和静态转换函数,例如std::dynamic_pointer_cast()
有多种方法。下面的内容是最复杂、最合理的。它需要在类型定义中进行大量的工作,但会产生使用这些类型的最干净的“客户机”代码
现在是学习如何使字体规则的时候了
常规类型的实例的行为类似于值。C++算法和容器的工作方式比正则类型要好得多。
template<class K>
class E_interface {
public:
virtual ~E_interface() {};
virtual void init() = 0;
virtual void insert(const K& k) = 0;
virtual size_t count() const = 0;
virtual void copy_from(const E_interface& x) = 0;
std::unique_ptr<E_interface> clone() const = 0;
};
clone_ptr
是一个智能指针,它是一个唯一的\u ptr
,知道如何通过调用存储对象上的clone()
和copy_from
来复制自身。它可能有一些拼写错误
现在我们写下我们的E:
template<class K>
class E {
clone_ptr<E_interface<K>> pImpl;
public:
E() = default;
E( std::unique_ptr<E_interface<K>> in ):pImpl(std::move(in)) {}
E( E const& )=default;
E( E && )=default;
E& operator=( E const& )=default;
E& operator=( E && )=default;
explicit operator bool() const { return (bool)pImpl; }
void init() { if (*this) pImpl->init(); }
void insert(const K& k) ( if (*this) pImpl->insert(k); }
size_t count() const { if (*this) pImpl->count(); else return 0; }
};
给我们
template<class K>
using Eone = E_impl< Eone_impl, K >;
template<class K>
using Etwo = E_impl< Etwo_impl, K >;
或者类似的
你的部分问题是你必须问自己“复制E
意味着什么”。在C++中,你自己回答这个问题;根据您的回答方式,您可能被允许或不被允许将其存储在std::vector
std::vector
是一个基于值的类中。vector
没有意义,因为它将存储抽象类的值。“我想限制用户实例化它”-但是。。。编译器将为您这样做,因为纯虚拟函数-事实上,您甚至可以稍后在clone()
函数中声明这一点,并且(智能)指针是您的朋友。virtual void copy(const E&x)=0
多态副本是一罐您不想打开的蠕虫。避免。你有Java背景吗?为什么shared\u ptr
?默认的go-to智能指针应该是唯一的\u ptr
。这并不能回答以下问题:如何使用n
副本e
初始化std::vector
,e
是常量&
?这确实是一个优雅(但有点复杂)的解决方案。然而,我相信你的最后一段是主要的外卖。显然,我可能只需要使用一个指向E
的指针数组,并在其中存储EOne
和ETwo
对象就可以了。然而,这确实是一个复杂的问题,我目前无法具体回答(即,这是一个正在进行的项目)。但是,我要感谢您花时间和精力编译这个答案。@nick.katsip哑指针(原始指针)不适合放入std::vector
s,因为vector
s希望它们的内容能够以合理的方式移动,而且资源跟踪变得困难<代码>值\u ptr
尝试制作一个足够智能的指针,以便复制和移动unique\u ptr
是一个只移动的指针(它不允许你复制10个副本)。那么,你建议我使用哪一个<代码>值\u ptr或唯一\u ptr
?当我试图使用unique\u ptr
并用std::move()
将其提供给std::vector::push\u back()
时,我遇到了一个错误,无法调用抽象类的构造函数。具体地说,在构造函数中,我将v
更改为std::vector
,在我得到一个唯一的\u ptr p
对象之后,我做了v.push_back(std::move(p))
。然后,编译器给我一个错误,我不能调用抽象类的构造函数。有什么建议吗?@nick.katsip您可以返回到一个唯一指针向量中,这意味着您的评论没有完全描述您的问题。试着画一个解决方案的草图,然后问一个新的问题,关于你所遇到的错误。一定要发一封信。
template<class T, class D=std::default_delete<D>, class Base=std::unique_ptr<T>>
struct clone_ptr:Base {
using Base::Base;
clone_ptr(Base&& b):Base(std::move(b)) {}
clone_ptr()=default;
clone_ptr(clone_ptr&&o)=default;
clone_ptr(clone_ptr const& o):
clone_ptr(
o?clone_ptr(o->clone()):clone_ptr()
)
{}
clone_ptr& operator=(clone_ptr&&o)=default;
clone_ptr& operator=(clone_ptr const&o) {
if (*this && o) {
get()->copy_from(*o.get());
} else {
clone_ptr tmp(o);
*this = std::move(tmp);
}
return *this;
}
};
template<class K>
class E {
clone_ptr<E_interface<K>> pImpl;
public:
E() = default;
E( std::unique_ptr<E_interface<K>> in ):pImpl(std::move(in)) {}
E( E const& )=default;
E( E && )=default;
E& operator=( E const& )=default;
E& operator=( E && )=default;
explicit operator bool() const { return (bool)pImpl; }
void init() { if (*this) pImpl->init(); }
void insert(const K& k) ( if (*this) pImpl->insert(k); }
size_t count() const { if (*this) pImpl->count(); else return 0; }
};
template<class Impl, class K>
struct E_impl: E<K> {
using E<K>::E<K>;
E_impl() : E<K>( std::make_unique<Impl>() ) {}
template<class...Args>
E_impl(Args&&...args) : E<K>( std::make_unique<Impl>(std::forward<Args>(args)...) ) {}
};
template<class K>
using Eone = E_impl< Eone_impl, K >;
template<class K>
using Etwo = E_impl< Etwo_impl, K >;
J<std::string> j(10, std::make_unique<EOne<std::string>>(e))